home *** CD-ROM | disk | FTP | other *** search
/ PsL Monthly 1993 December / PSL Monthly Shareware CD-ROM (December 1993).iso / prgmming / dos / c / iostrm.exe / IOSTREAM < prev   
Text File  |  1991-01-02  |  92KB  |  3,134 lines

  1. ************************* INTRODUCTION *************************
  2.  
  3. This document is a tutorial on the use of the header file <iostream.h>, as
  4. implemented by Borland International, Inc. in its product Turbo C++.
  5.  
  6. There are 4 main sections:
  7.  
  8.    1) Header file
  9.    2) Output
  10.    3) Input
  11.    4) Manipulators
  12.    5) File I/O
  13.  
  14. These sections are actually just part of the complete set of notes on the C++
  15. language that I use in my programming classes here in Silicon Valley. Before
  16. you begin this tutorial, you must be familiar with C, know how to write simple 
  17. classes, have some knowledge of member functions, can create instances of
  18. classes, etc.
  19.  
  20. I have spent many hours putting this material together, and hope that it
  21. serves its intended purpose, which is to give CIS subscribers an understand-
  22. ing of <iostream.h> that none of the manuals or textbooks seem to provide. 
  23. I am deeply indebted to John Dlugosz, with whom many of you are already 
  24. familiar, for taking the time out of his busy schedule, to proof-read this 
  25. tutorial. Without his help and guidance, the information contained herein 
  26. would not be as accurate and complete as (I hope!) it is. Nevertheless, if 
  27. you find an error, or have a suggestion as to how this tutorial can be 
  28. improved, please let me know.
  29.  
  30. Eric Nagler         CIS 76357,1146
  31. P. O. Box 2483
  32. Santa Clara, California 95055-2483
  33.  
  34.  
  35. *********************** SECTION 1 --  HEADER FILE ***************************
  36.  
  37. All program examples in this tutorial include a file called <header.h>. It is
  38. my own creation (so don't call Borland!), and is tailored to accommodate
  39. all of the program examples. I suggest that you copy and use this header file 
  40. if you wish to execute the examples. But feel free to modify it according to 
  41. your own needs.
  42.  
  43. If the examples sometimes appear to be "scrunched" toward the left-hand side
  44. of the screen, it's because they are designed to be shown in 40-column mode,
  45. double height.
  46.  
  47.  ////////////////////////////////////
  48. // My private header file for C++ programs
  49. ////////////////////////////////////
  50.  
  51. // There's also a #define ZORTECH in my Zortech header file so that I can
  52. // write different statements to print addresses.
  53.  
  54. #define BORLAND
  55.  
  56. // OLD is defined in the cc.bat file which I use to compile Turbo C++
  57. // using the old (version 1.2) style I/O. Therefore, use <stream.h>
  58.  
  59. #ifdef OLD
  60. #include <stream.h>
  61.  
  62. // Otherwise, it must be version 2.0, so use <fstream.h>, which also
  63. // includes <iostream.h>
  64.  
  65. #else
  66. #include <fstream.h>
  67.  
  68. // Any manipulators taking a parameter will also be accommodated
  69.  
  70. #include <iomanip.h>
  71. #endif
  72.  
  73. // I also need console I/O for the PAUSE() function
  74.  
  75. #include <conio.h>
  76.  
  77. // Include <stdio.h> for C style I/O
  78.  
  79. #include <stdio.h>
  80.  
  81. // Include these because they're used so frequently, and really don't add
  82. // that much to the compilation time
  83.  
  84. #include <string.h>
  85. #include <ctype.h>
  86. #include <stdlib.h>
  87. #include <time.h>
  88.  
  89. ///////////////////////////////////
  90.  
  91. // My private defines
  92.  
  93. #define FALSE               0
  94. #define TRUE                !FALSE
  95. #define AND                 &&
  96. #define OR                  ||
  97. #define NO                  0
  98. #define YES                 !NO
  99. #define EQUALS              ==
  100. #define IS_EQUAL_TO         ==
  101. #define NOT                 !
  102. #define IS_NOT_EQUAL_TO     !=
  103. #define NOT_EQUAL_TO        !=
  104. //
  105. #define BLANK               ' '
  106. #define SPACE               ' '
  107. #define ASTERISK            '*'
  108. #define DECIMAL             '.'
  109. #define NEW_LINE            '\n'
  110. #define NUL                 '\0'
  111. #define TAB                 '\t'
  112. #define BACKSPACE           '\b'
  113. #define BEEP                '\a'
  114. #define FORMFEED            '\f'
  115. #define RETURN              '\r'
  116.  
  117. ///////////////////////////////////
  118.  
  119. // My private PAUSE function
  120.  
  121. void PAUSE()
  122. {
  123.    cout << "Press any key to "
  124.         << "continue...\n" ;
  125.    getch() ;
  126. }
  127.  
  128. // My private flush-the-input-buffer manipulator until either EOF or
  129. // new-line is found.
  130.  
  131. istream& FLUSH(istream& strm)
  132. {
  133.    strm.clear() ;
  134.    char ch ;
  135.    while (!strm.get(ch).eof() AND ch != NEW_LINE)
  136.                          ;  // Empty body
  137.    return strm ;
  138. }
  139.  
  140. ////////////////////////////////////
  141. // This function prints the various I/O flags of an input stream.
  142. // Defaults to 'cin'
  143.  
  144. void IOFLAGS(istream& stream=cin)
  145. {
  146.    cout << "eof state is  " << (stream.eof()
  147.            ? "ON" : "OFF") << endl ;
  148.    cout << "good state is " << (stream.good()
  149.            ? "ON" : "OFF") << endl ;
  150.    cout << "fail state is " << (stream.fail()
  151.            ? "ON" : "OFF") << endl ;
  152.    cout << "bad state is  " << (stream.bad()
  153.            ? "ON" : "OFF") << endl ;
  154.    cout << "if (!instance) returns "<< (!stream ? "TRUE" : "FALSE") << endl ;
  155.    cout << "if (instance) returns " << (stream ? "TRUE" : "FALSE") << endl ;
  156. }
  157.  
  158. /////////////////////////////////////
  159. // This function prints the format flags of an output stream.
  160. // Defaults to 'cout'
  161.  
  162. void FORMATFLAGS(ostream& stream=cout)
  163. {
  164.    static char* message[] =
  165.    {
  166.      "skipws" ,
  167.      "left" ,
  168.      "right" ,
  169.      "internal" ,
  170.      "dec" ,
  171.      "oct" ,
  172.      "hex" ,
  173.      "showbase" ,
  174.      "showpoint" ,
  175.      "uppercase" ,
  176.      "showpos" ,
  177.      "scientific" ,
  178.      "fixed" ,
  179.      "unitbuf" ,
  180.      "stdio"
  181.    } ;
  182.  
  183.    cout << "FORMAT FLAGS\n" ;
  184.    long f = stream.flags() ;
  185.    for (int i = 0 ; i < 16 ; ++i)
  186.    {
  187.      if (f & 0x0001)
  188.        cout << message[i] << endl ;
  189.      f >>= 1 ;
  190.    }
  191. }
  192.  
  193. ///////////////////////////////////
  194.  
  195. // Define a global instance of the
  196. // class 'ofstream' called POUT that
  197. // is tied to the printer
  198.  
  199. ofstream POUT("prn") ;
  200.  
  201. /////////////////////////////////////
  202.  
  203. // A manipulator that directs to the printer all subsequent output for
  204. // the one statement in which it is found
  205.  
  206. ostream& PRINTER(ostream&)
  207. {
  208.    return POUT ;
  209. }
  210.  
  211. // A manipulator that directs to the screen all subsequent output for
  212. // the one statement in which it is found
  213.  
  214. ostream& SCREEN(ostream&)
  215. {
  216.    return cout ;
  217. }
  218.  
  219. // A manipluator to set left justification
  220.  
  221. ostream& LEFT(ostream& str)
  222. {
  223.    str.setf(ios::left , ios::adjustfield) ;
  224.    return str ;
  225. }
  226.  
  227. // A manipluator to set right justification
  228.  
  229. ostream& RIGHT(ostream& str)
  230. {
  231.    str.setf(ios::right , ios::adjustfield) ;
  232.    return str ;
  233. }
  234.  
  235. // A manipluator to set internal justification
  236.  
  237. ostream& INTERNAL(ostream& str)
  238. {
  239.    str.setf(ios::internal , ios::adjustfield) ;
  240.    return str ;
  241. }
  242.  
  243. // A manipulator to show the decimal point
  244.  
  245. ostream& SHOWPOINT(ostream& str)
  246. {
  247.    str.setf(ios::showpoint) ;
  248.    return str ;
  249. }
  250.  
  251. // A manipulator to show the base on hex and octal output
  252.  
  253. ostream& SHOWBASE(ostream& str)
  254. {
  255.    str.setf(ios::showbase) ;
  256.    return str ;
  257. }
  258.  
  259. // A manipulator to suppress the showing of the base
  260.  
  261. ostream& NOSHOWBASE(ostream& str)
  262. {
  263.    str.unsetf(ios::showbase) ;
  264.    return str ;
  265. }
  266.  
  267. // A manipulator to show fixed point output
  268.  
  269. ostream& FIXED(ostream& str)
  270. {
  271.    str.setf(ios::fixed , ios::floatfield) ;
  272.    return str ;
  273. }
  274.  
  275. // A manipulator to show scientific point output
  276.  
  277. ostream& SCIENTIFIC(ostream& str)
  278. {
  279.    str.setf(ios::scientific , ios::floatfield) ;
  280.    return str ;
  281. }
  282.  
  283. // A manipulator to show uppercase output on hex and scientific
  284. // numbers
  285.  
  286. ostream& UPPERCASE(ostream& str)
  287. {
  288.    str.setf(ios::uppercase) ;
  289.    return str ;
  290. }
  291.  
  292. // A manipulator to show lowercase output on hex and scientific
  293. // numbers
  294.  
  295. ostream& LOWERCASE(ostream& str)
  296. {
  297.    str.unsetf(ios::uppercase) ;
  298.    return str ;
  299. }
  300.  
  301. // A manipulator to show a '+' on positive numbers
  302.  
  303. ostream& SHOWPOS(ostream& str)
  304. {
  305.    str.setf(ios::showpos) ;
  306.    return str ;
  307. }
  308.  
  309. // A manipulator to negate showing a '+' on positive numbers
  310.  
  311. ostream& NOSHOWPOS(ostream& str)
  312. {
  313.    str.unsetf(ios::showpos) ;
  314.    return str ;
  315. }
  316.  
  317. *********************** SECTION 2 -- OUTPUT *********************************
  318.  
  319. Introduction
  320.  
  321. Whenever data gets sent to a text output device, it takes on the form of a
  322. stream of characters. For example, the floating point number 1.234 is not
  323. stored internally as 5 characters ('1' , '.' , '2' , '3' , '4'), but rather 
  324. in a special format designed to accommodate floating point values. In character
  325. format, this value is meaningless. Yet, if you were to print this number,
  326. you certainly would want to have the aforementioned 5 characters appear
  327. on your output device.
  328.  
  329. The C++ input/output mechanism provided with AT&T release 2.0
  330. provides a series of classes that have been created to handle the problem of
  331. sending and receiving data. This mechanism consists of many classes, some
  332. derived from others, and some contained within others. At the lowest level,
  333. the most fundamental operation is to manipulate the characters within some
  334. buffer, also known as a stream. This is done by the class "streambuf".
  335.  
  336. Because input and output must be formatted to be legible, another class
  337. called "ios" contains functions and data to handle this task. When an instance
  338. of the class "ios" comes into existence, it receives a pointer to some
  339. "streambuf" area. To send the actual formatted output to the user, another
  340. class called "ostream" (which is derived from "ios") is used.
  341.  
  342. Classes, like built-in scalar types, don't occupy any memory. What is
  343. needed, then, is an instance, or object, of that class type. In the hierarchy 
  344. of derivation, the last class,  ostream , is the one that used to create the
  345. instance, as follows:
  346.  
  347.    ostream cout ;
  348.  
  349. Since the instance "cout" is an instance of a class that has been derived from
  350. parent classes, by definition it has inherited all of the data members of its
  351. parent classes, and has all of the functionality of those classes. Also, since
  352. this instance is defined at global scope, your program has unlimited access
  353. to it at all times. Output operations are initiated using the instance "cout".
  354.  
  355. In addition to data members, classes can contain functions to operate upon
  356. these members. In the class  ostream , the function you will use the most
  357. often is called the insertion operator, and its name is "operator<<". The
  358. argument to this function is the data item that you wish to output. The name
  359. 'insertion' comes from the fact that you are 'inserting' items into an
  360. output buffer.
  361.  
  362. In a manner similar to that of accessing a data member of a structure,
  363. function members of a class are also accessed using the direct member
  364. operator, also known as the dot operator (.). This is done by first writing
  365. the instance, followed by the dot operator, and then the function name with
  366. any arguments enclosed within parentheses. For example, to output a simple
  367. message, you would code:
  368.  
  369.    cout.operator<<("THE ANSWER IS ") ;
  370.  
  371. where "THE ANSWER IS " is the argument to the function "operator<<".
  372. Similarly, to output the number 65, you would code:
  373.  
  374.    cout.operator<<(65) ;
  375.  
  376. To output a new-line character, you would code:
  377.  
  378.    cout.operator<<('\n') ;
  379.  
  380. or, if you wish, a string containing nothing but a new-line character:
  381.  
  382.    cout.operator<<("\n") ;
  383.  
  384. If you really think about it, you should be asking the obvious question,
  385. "How can a function take a single argument of different types?" In other
  386. words, in the first call above a string (type "char*") was passed as the
  387. argument, in the second call an integer (type "int") was passed, and in the
  388. third a character (type "char") was passed. How can this be? The answer is
  389. that the function "operator<<" has been "overloaded", so that many versions
  390. of the "same function" exist within the class "ostream". The compiler is smart
  391. enough to distinguish one version from another, so that your function call
  392. correctly accesses the function specifically written to handle the type of
  393. argument that you provide.
  394.  
  395. The next obvious question you should be asking is whether you have to
  396. code a series of such function calls if more than one data item is to be
  397. output. In other words, in the examples above, are three separate function
  398. calls really necessary? Fortunately, the answer is no. The way the
  399. "operator<<" function is written, a reference (address) to the calling
  400. instance ( cout ) is returned by the function, and can therefore be used as the
  401. calling instance for a concatenated function call. That is, the three function
  402. calls can be written:
  403.  
  404.    cout.operator<<("THE ANSWER IS ")
  405.        .operator<<(65)
  406.        .operator<<('\n') ;
  407.  
  408. That's the good news. The bad news is that it's still too much coding and
  409. still too awkward. With this in mind, the designers of C++ allow the
  410. programmer to abbreviate the notation:
  411.  
  412.    cout.operator<<(argument1) ;
  413.  
  414. with the more convenient:
  415.  
  416.    cout << argument1 ;
  417.  
  418. and the notation:
  419.  
  420.    cout.operator<<(argument1).operator<<(argument2) ;
  421.  
  422. with the more convenient:
  423.  
  424.    cout << argument1 << argument2 ;
  425.  
  426. Note that the dot operator has been eliminated, and the function
  427. "operator<<" has been replaced with just the insertion operator "<<".
  428.  
  429. For stylistic purposes you could write each insertion operator on its own
  430. line. Try running this program.
  431.  
  432.   // EXAMPLE OUTPUT-01
  433.  
  434.  #include <header.h>
  435.  
  436.  int main()
  437.  {
  438.     cout << "THE ANSWER IS "
  439.          << 65
  440.          << "\n" ;
  441.  
  442.     return 0 ;
  443.  }
  444.  
  445. Only one such occurrence of "cout" needs to be written until the end of the
  446. statement is reached.
  447.  
  448. Of course, you could restrict each statement to having just one insertion
  449. operator. This program produces exactly the same output as before.
  450.  
  451.  // EXAMPLE OUTPUT-02
  452.  
  453.  #include <header.h>
  454.  
  455.  int main()
  456.  {
  457.     cout << "THE ANSWER IS " ;
  458.     cout << 65 ;
  459.     cout << "\n" ;
  460.  
  461.     return 0 ;
  462.  }
  463.  
  464. In addition to a string, an integer, and a character, the function
  465. "operator<<" has been overloaded to accept arguments of type "long", "float",
  466. "double", pointer, and so forth.
  467.  
  468. ******************************************************************
  469. Bit Format Flags
  470.  
  471. Now think about a "printf" function call. It usually consists of a control
  472. string argument and, optionally, a list of expressions to be output. The
  473. control string contains literals which will be output exactly as shown, and
  474. conversion specifications that indicate exactly how an expression from the
  475. list of expressions is to appear. Each conversion specification starts with a
  476. '%' and ends with a conversion character, e.g., 'd' for decimal format, 'c' for
  477. character format, 's' for a string, etc. Between the start and end you may
  478. enter various flags, the field width, base formatting, justification, floating
  479. point precision, and so forth. Each conversion specification stands on its
  480. own; there is no connection to any other one.
  481.  
  482. In the C++ version 2.0 stream I/O, all of the characteristics relating to how
  483. an expression should appear apply, not to each individual expression, but to
  484. the output stream as a whole . In other words, once you specify that decimal
  485. format is desired, ALL integer numbers from that point on are output in
  486. decimal format. No further action need be taken. If you decide to switch to
  487. hexadecimal output, then all integer numbers from that point on will be
  488. shown in their hex formats. The same is true for floating point precision.
  489. Once it is set, it stays set for all subsequent floating point numbers. (There
  490. is one important exception to the "set it and forget it" feature of C++
  491. streaming that will be discussed later).
  492.  
  493. Any binary characteristic of the output stream is stored in a long
  494. (protected) field in the class "ios". In Turbo C++ this field is called
  495. "x_flags". (The fact that it's  protected  means that you cannot access it
  496. directly.) Each characteristic occupies one bit of this field, which simply
  497. means that it's either true or false; on or off; set or not set. For example,
  498. the output state of decimal is either on or off. The same can be said for the
  499. output states of hexadecimal and octal. Also, the state of left-justification 
  500. is either set or not set, as is its opposite, right-justification. On the other
  501. hand, stream characteristics that require values, such as the field width and
  502. floating point precision, are stored in integer variables.
  503.  
  504. Each binary characteristic is represented by a unique value in a field that is
  505. part of an unnamed public enumerated type in the class "ios". This value is
  506. represented by exactly one bit in the field. Thus, no two characteristics will
  507. ever have the same bit position (ranging from 15 down to 0) set on. By
  508. ORing these bits into the field "x_flags", the different states can be set with
  509. no conflict. This allows someone examining the field "x_flags" to infer with
  510. no ambiguity which characteristics are on and which are off.
  511.  
  512. Each binary characteristic also has a name associated with it that you may
  513. reference. The complete list of all enumerated values is shown below.
  514. Because these names exist within the class "ios", the name of this class must
  515. be specified in conjunction with the scope resolution operator (::) to
  516. unambiguously access a specific value. These are the names and values for
  517. Turbo C++:
  518.  
  519.  NAME            VALUE    MEANING
  520.  
  521.  ios::skipws     0x0001   Skip whitespace on input
  522.  ios::left       0x0002   Left-justification of output
  523.  ios::right      0x0004   Right-justification of output
  524.  ios::internal   0x0008   Pad after sign or base indicator
  525.  ios::dec        0x0010   Show integers in decimal  format
  526.  ios::oct        0x0020   Show integers in octal format
  527.  ios::hex        0x0040   Show integers in hexadecimal format
  528.  ios::showbase   0x0080   Show the base for octal and hex numbers
  529.  ios::showpoint  0x0100   Ensure that the decimal point is shown for all
  530.                           floating point numbers
  531.  ios::uppercase  0x0200   Show uppercase hex numbers
  532.  ios::showpos    0x0400   Show + for positive numbers
  533.  ios::scientific 0x0800   Use exponential notation on floating point numbers
  534.  ios::fixed      0x1000   Use fixed decimal output on floating point numbers
  535.  ios::unitbuf    0x2000   Flush all streams after insertion
  536.  ios::stdio      0x4000   Flush stdout and stderr after insertion
  537.  
  538. Because we will be examining these bits very carefully in the coming
  539. examples, it is very useful to have a function to clearly display the status
  540. for us. This has been done in the function "FORMATFLAGS" which is
  541. contained in the file "header.h". This function takes one argument: an
  542. instance of an output stream. If no argument is supplied, then the function
  543. defaults to using the name "cout".
  544.  
  545. Try running this test. Are any of these enumerated bits in the field "x_flags"
  546. already on when your program first gets control? This little program will
  547. provide the answer.
  548.  
  549.  // EXAMPLE OUTPUT-11
  550.  
  551.  // TEST THE DEFAULT OF x_flags
  552.  
  553.  #include <header.h>
  554.  
  555.  int main()
  556.  {
  557.    FORMATFLAGS() ;
  558.  }
  559.  
  560. The output of this program is:
  561.  
  562. FORMAT FLAGS
  563. skipws
  564. unitbuf
  565.  
  566. The next item of concern is how to turn these settings on and off. Within
  567. the class "ios" there are several member functions provided that allow this to
  568. be done. The first of these functions is called "setf". Remember: to call it,
  569. you must first specify the instance name, "cout", the dot member operator,
  570. and then the function name. Thus, you would write:
  571.  
  572.    cout.setf
  573.  
  574. The function "setf" has been overloaded to accept either one or two
  575. arguments. In both cases, the first argument specifies which bits are to be
  576. turned on in the field "x_flags".
  577.  
  578. For example, to turn on the  ios::dec  bit, you would code:
  579.  
  580.    cout.setf(ios::dec) ;
  581.  
  582. The function "setf" works by ORing its first argument into the field
  583. "x_flags", thereby leaving any other bits in this field undisturbed. This means
  584. that it's possible to turn on more than one bit with just one call to "setf" by
  585. using an expression for the first argument that contains several bits ORed
  586. together. For example, to turn on the "ios::dec" and the "ios::right" bits, you
  587. would code:
  588.  
  589.   cout.setf(ios::dec | ios::right) ;
  590.  
  591. How can you turn the bits off? Use the member function "unsetf". This
  592. function takes exactly one argument: the bit pattern to be turned off. Thus,
  593. to turn off the bit "ios::dec", you would code:
  594.  
  595.   cout.unsetf(ios::dec) ;
  596.  
  597. Like "setf", more than one bit at a time can be turned off by ORing the
  598. enumerated values together in the argument field.
  599.  
  600. Unfortunately, the previous method of turning bits on and off is awkward
  601. because in many cases the bits are mutually exclusive, and it would
  602. normally take 2 function calls to (a) turn a bit off using "unsetf", and (b)
  603. turn another bit on using "setf". Fortunately, a better way exists by using the
  604. "setf" function with 2 arguments. In this case the second argument represents
  605. those specific bits which are to be turned OFF prior to having those bits
  606. turned ON that are specified by the logical AND of the first and second
  607. arguments. For example, to turn the bit "ios::dec" ON and ensure that the
  608. mutually exclusive bits "ios::oct" and "ios::hex" are OFF, you would code:
  609.  
  610.    cout.setf(ios::dec , ios::dec | ios::oct | ios::hex) ;
  611.  
  612. To prove this, run this program:
  613.  
  614.  // EXAMPLE OUTPUT-12
  615.  
  616.  // TEST TURNING ON FORMAT FLAG BITS
  617.  
  618.  #include <header.h>
  619.  
  620.  int main()
  621.  {
  622.     cout.setf(ios::oct | ios::hex) ;
  623.     FORMATFLAGS() ;
  624.     cout.setf(ios::dec , ios::dec | ios::oct | ios::hex) ;
  625.     FORMATFLAGS() ;
  626.  
  627.     return 0 ;
  628.  }
  629.  
  630. The output of this program is:
  631.  
  632. FORMAT FLAGS
  633. skipws
  634. oct
  635. hex
  636. unitbuf
  637. FORMAT FLAGS
  638. skipws
  639. dec
  640. unitbuf
  641.  
  642. Because "ios::dec", "ios::oct" and "ios::hex" are mutually exclusive bit fields
  643. (that is, you only want ONE of them on at any time), you would normally
  644. AND the one bit of the first argument of "setf" with the OR of all 3 bits, as
  645. shown above. The second argument can also be specified as "ios::basefield",
  646. where this value is pre-defined as: "ios::dec | ios::oct | ios::hex".
  647.  
  648. For example, program OUTPUT-12 can be re-written as:
  649.  
  650.  // EXAMPLE OUTPUT-13
  651.  
  652.  // TEST ios::basefield
  653.  
  654.  #include <header.h>
  655.  
  656.  int main()
  657.  {
  658.     cout.setf(ios::oct | ios::hex) ;
  659.     FORMATFLAGS() ;
  660.     cout.setf(ios::dec , ios::basefield) ;
  661.     FORMATFLAGS() ;
  662.  
  663.     return 0 ;
  664.  }
  665.  
  666. The output of this program is the same.
  667.  
  668. In a similar manner, the field "ios::adjustfield" represents the bit positions
  669. of "ios::left", "ios::right" and "ios::internal" ORed together, and the field
  670. "ios::floatfield" represents the bit positions of "ios::fixed" and
  671. "ios::scientific" ORed together.
  672.  
  673. Because the field "x_flags" in the class "ios" is protected, this means that
  674. you cannot access it directly. However, there is a public member function
  675. called "flags" that will return this field to you. If you provide a long integer
  676. as an argument to "flags", then the existing value of "x_flags" will be
  677. returned to you after your argument is used to provide a new setting for
  678. "x_flags".
  679.  
  680. For example:
  681.  
  682.  // EXAMPLE OUTPUT-14
  683.  
  684.  // TEST THE flags MEMBER FUNCTION
  685.  
  686.  #include <header.h>
  687.  
  688.  int main()
  689.  {
  690.     long value = cout.flags(0) ;
  691.     cout.setf(ios::hex , ios::basefield) ;
  692.     cout << "value is "
  693.          << value
  694.          << '\n' ;
  695.     FORMATFLAGS(cout) ;
  696.  
  697.     return 0 ;
  698.  }
  699.  
  700. The output of this program is:
  701.  
  702. value is 2001
  703. FORMAT FLAGS
  704. hex
  705.  
  706. Note that "value" is the old value of "x_flags", and is printed in hexadecimal.
  707. The '2' represents the "unitbuf" bit, and the '1' is the "skipws" bit. There is
  708. nothing shown under the heading "FORMAT FLAGS" except "hex" because
  709. all of the bits were turned off by the call to "flags", then the hex bit was
  710. turned back on.
  711.  
  712. Both the "setf" and "unsetf" functions return a value, which you are free to
  713. use or ignore. The value returned is a long integer representing the
  714. previous value of the field "x_flags". However, you will probably never
  715. have occasion to use this value.
  716.  
  717. ******************************************************************
  718. The Base Setting and Integer Output
  719.  
  720. Output formatting is important because you want to have complete
  721. flexibility in the manner in which your data appears. Let's start with the
  722. base in which integers will be shown. If a "printf" function call, you have 3
  723. choices: decimal, octal and hex. A decimal output can be obtained by using
  724. a conversion specification of "%d" or "%i", an octal by using "%o", and hex by
  725. using "%x" or "%X". (How to emulate lower vs. upper case will be discussed
  726. later.) There are 3 bits in the enumerated values shown in the Bit Format
  727. Flags section that control the base setting:
  728.  
  729.    ios::dec    0x0010     Show integers in decimal format
  730.    ios::oct    0x0020     Show integers in octal format
  731.    ios::hex    0x0040     Show integers in hexadecimal format
  732.  
  733. To guarantee that decimal output is used, you must turn on the bit
  734. "ios::dec", and ensure that all the remaining 2 bits are turned off. The same
  735. reasoning applies to octal and hex output. But we proved in example
  736. OUTPUT-11 that no bit pertaining to the output base is on by default.
  737. Therefore, which base will be used? The answer is that the compiler will
  738. default to decimal output if none of the 3 base field bits is on. But be
  739. careful! If more than one output base bit happends to be on, then the output
  740. is unpredictable. (Of course, you would never deliberately put yourself in
  741. this situation.). Remember: Once the base has been set, it stays set for all
  742. future integers unless it is subsequently changed.
  743.  
  744. Recall that the field "ios::basefield" has been defined for you to contain all
  745. 3 base field bits ORed together, and should be used in the second parameter
  746. of "setf" to ensure that all 3 bits are turned off before altering them. So now
  747. let's create a program to output the number 65 using the default base,
  748. followed by the base in octal, hexadecimal, and decimal. (NOTE: a better
  749. way in which to write this program will be shown in the section on
  750. manipulators.)
  751.  
  752.  // EXAMPLE OUTPUT-21
  753.  
  754.  // HOW TO PRINT IN DECIMAL, OCTAL
  755.  // AND HEXADECIMAL FORMATS
  756.  
  757.  #include <header.h>
  758.  
  759.  int main()
  760.  {
  761.     cout << 65 << '\n' ;
  762.     cout.setf(ios::oct , ios::basefield) ;
  763.     cout << 65 << '\n' ;
  764.     cout.setf(ios::hex , ios::basefield) ;
  765.     cout << 65 << '\n' ;
  766.     cout.setf(ios::dec , ios::basefield) ;
  767.     cout << 65 << '\n' ;
  768.  
  769.     return 0 ;
  770.  }
  771.  
  772. The output of this program, as expected, is:
  773.  
  774. 65
  775. 101
  776. 41
  777. 65
  778.  
  779. One final point: In a "printf" function call, the use of the flag # causes the
  780. base of an octal or hexadecimal number to appear (0 and 0x, respectively).
  781. The same effect can be achieved in C++ by setting on the bit "ios::showbase".
  782. Here is example OUTPUT-21 again, but this time the base of the octal and
  783. hexadecimal numbers is shown. To turn off this feature, use the "unsetf"
  784. function.
  785.  
  786.  // EXAMPLE OUTPUT-22
  787.  
  788.  // HOW TO PRINT IN DECIMAL, OCTAL
  789.  // AND HEXADECIMAL FORMATS AND SHOW
  790.  // THE BASE FOR OCTAL AND HEX
  791.  // NUMBERS
  792.  
  793.  #include <header.h>
  794.  
  795.  int main()
  796.  {
  797.     cout.setf(ios::showbase) ;
  798.     cout << 65 << '\n' ;
  799.     cout.setf(ios::oct , ios::basefield) ;
  800.     cout << 65 << '\n' ;
  801.     cout.setf(ios::hex , ios::basefield) ;
  802.     cout << 65 << '\n' ;
  803.     cout.setf(ios::dec , ios::basefield) ;
  804.     cout << 65 << '\n' ;
  805.  
  806.     return 0 ;
  807.  }
  808.  
  809. The output of this program is:
  810.  
  811. 65
  812. 0101
  813. 0x41
  814. 65
  815.  
  816. Note that on positive decimal output, a '+' sign is assumed. If you want this
  817. sign to appear, turn on the bit "ios::showpos". (Of course, if the number is
  818. negative, the '-' sign will always appear.) To turn off this feature, use the
  819. "unsetf" function. In this example the number 65 is displayed with a '+' sign.
  820.  
  821.  // EXAMPLE OUTPUT-23
  822.  
  823.  // HOW TO SHOW THE SIGN OF A POSITIVE
  824.  // NUMBER
  825.  
  826.  #include <header.h>
  827.  
  828.  int main()
  829.  {
  830.     cout.setf(ios::showpos) ;
  831.     cout << 65 << '\n' ;
  832.  
  833.     return 0 ;
  834.  }
  835.  
  836. The output of this program is:
  837.  
  838. +65
  839.  
  840. There is one other option you can employ with hexadecimal numbers. By
  841. default any hex digit, as well as the 'x' in the base, appears in lower-case.
  842. The same rule applies to the 'e' when printing in scientific notation. If you
  843. want to see upper-case, turn on the bit "ios::uppercase". To revert back to
  844. lower-case, use the "unsetf" function.
  845.  
  846. This example prints the number 171 in hexadecimal, and shows all hex
  847. digits in upper-case.
  848.  
  849.  // EXAMPLE OUTPUT-24
  850.  
  851.  // HOW TO PRINT HEX DIGITS IN
  852.  // UPPER CASE LETTERS
  853.  
  854.  #include <header.h>
  855.  
  856.  int main()
  857.  {
  858.     cout.setf(ios::uppercase | ios::showbase) ;
  859.     cout.setf(ios::hex , ios::basefield) ;
  860.     cout << 171 << '\n' ;
  861.  
  862.     return 0 ;
  863.  }
  864.  
  865. The output of this program is:
  866.  
  867. 0XAB
  868.  
  869. *****************************************************************
  870. Character Output
  871.  
  872. Integer output pertains to the display of decimal, octal and hexadecimal
  873. numbers. The next question is: Can you emulate "%c" in a "printf" function
  874. call to set the base for character output, i.e., set it so that all integral
  875. values appear in their character representations? Unfortunately, the answer
  876. is no. However, the problem only arises when a non-character value needs to be
  877. displayed in its character form, because if you define a character using type
  878. char , then it will automatically be shown in its character format. Thus, to
  879. make a non-char type appear in character format, an explicit cast to type
  880. "char" is required.
  881.  
  882. For example, this program prints the letter 'A' five times:
  883.  
  884.  // EXAMPLE OUTPUT-31
  885.  
  886.  // HOW TO PRINT A CHARACTER AND A
  887.  // NON-CHARACTER IN CHARACTER
  888.  // FORMAT.
  889.  
  890.  #include <header.h>
  891.  
  892.  int main()
  893.  {
  894.     // No cast needed here
  895.     char ch1 = 'A' ;
  896.     cout << ch1 << '\n' ;
  897.     char ch2 = 65 ;
  898.     cout << ch2 << '\n' ;
  899.  
  900.     // Cast needed here
  901.     int ch3 = 65 ;
  902.     cout << (char)ch3 << '\n' ;
  903.     int ch4 = 0101 ;
  904.     cout << (char)ch4 << '\n' ;
  905.     int ch5 = 0x41 ;
  906.     cout << (char)ch5 << '\n' ;
  907.  
  908.     return 0 ;
  909.  }
  910.  
  911. How about the opposite? That is, suppose you want a character to be shown
  912. in its decimal, octal, and hexadecimal representations. Once again, a cast is
  913. required, this time to type "int". By doing this cast in conjunction with the
  914. proper base setting, the desired result can be obtained. In this example, the
  915. character "ch" is shown in its decimal, octal, and hexadecimal
  916. representations.
  917.  
  918.  // EXAMPLE OUTPUT-32
  919.  
  920.  // HOW TO PRINT A CHARACTER AS A
  921.  // DECIMAL, OCTAL AND HEXADECIMAL
  922.  // VALUE.
  923.  
  924.  #include <header.h>
  925.  
  926.  int main()
  927.  {
  928.     char ch = 'A' ;
  929.  
  930.     cout << (int)ch << '\n' ;
  931.     cout.setf(ios::oct , ios::basefield) ;
  932.     cout << (int)ch << '\n' ;
  933.     cout.setf(ios::hex , ios::basefield) ;
  934.     cout << (int)ch << '\n' ;
  935.  
  936.     return 0 ;
  937.  }
  938.  
  939. The output of this program is:
  940.  
  941. 65
  942. 101
  943. 41
  944.  
  945. There is another way to guarantee that an integral value gets shown in its
  946. character format. That is with the use of the member function called "put"
  947. (think of the C function "putchar"). This function always outputs its one
  948. argument in character format, regardless of how it was defined. This
  949. example prints the character 'A' three times.
  950.  
  951.  // EXAMPLE OUTPUT-33
  952.  
  953.  // HOW TO USE THE MEMBER FUNCTION
  954.  // put TO OUTPUT A CHARACTER
  955.  
  956.  #include <header.h>
  957.  
  958.  int main()
  959.  {
  960.     char ch1 = 'A' ;
  961.     int ch2 = 65 ;
  962.  
  963.     cout.put(ch1) << '\n' ;
  964.     cout.put('A') << '\n' ;
  965.     cout.put(ch2) << '\n' ;
  966.  
  967.     return 0 ;
  968.  }
  969.  
  970. ******************************************************************
  971. Setting the Field Width
  972.  
  973. The field width in C++ works in a similar manner to that of C. If the total
  974. number of characters needed for output is less than the specified width,
  975. then the extra spaces will be filled with the current fill character. If the
  976. number of characters is greater than the specified width, then the width is
  977. 'expanded' to accommodate the entire field. (In C the fill character in a
  978. "printf" function call can only be either a zero or a space; in C++ it can be
  979. any character you desire. This topic is dicussed following width.)
  980.  
  981. If no width is ever specified, then the default value of zero is assumed (just
  982. as it is in C). To change the field width, use the member function "width"
  983. with one argument: the width value itself. Then the next field to be output
  984. will use this value.
  985.  
  986. For example, this program prints the number 1 right-justified and preceded
  987. by 4 blanks, while the number 23 has 3 preceding blanks.
  988.  
  989.  // EXAMPLE OUTPUT-41
  990.  
  991.  // HOW TO SET THE FIELD WIDTH
  992.  
  993.  #include <header.h>
  994.  
  995.  int main()
  996.  {
  997.     cout.width(5) ;
  998.     cout << 1 << '\n' ;
  999.     cout.width(5) ;
  1000.     cout << 23 << '\n' ;
  1001.  
  1002.     return 0 ;
  1003.  }
  1004.  
  1005. The output of this program is:
  1006.  
  1007.     1
  1008.    23
  1009.  
  1010. Something should strike you as odd about this example. Why was it
  1011. necessary to write the line "cout.width(5)" twice? The answer is that the
  1012. width specification only applies to the next field to be output.  To prove this
  1013. statement, let's modify this example slightly and remove the second width
  1014. setting.
  1015.  
  1016.  // EXAMPLE OUTPUT-42
  1017.  
  1018.  // NOTE THAT THE WIDTH SETTING
  1019.  // ONLY APPLIES TO THE NEXT FIELD
  1020.  // TO BE OUTPUT
  1021.  
  1022.  #include <header.h>
  1023.  
  1024.  int main()
  1025.  {
  1026.     cout.width(5) ;
  1027.     cout << 1 << '\n' ;
  1028.     cout << 23  << '\n' ;
  1029.  
  1030.     return 0 ;
  1031.  }
  1032.  
  1033. The output of this program is:
  1034.  
  1035.     1
  1036. 23
  1037.  
  1038. Now the number 23 appears left-justified because the width reverted back
  1039. to its default value of 0.
  1040.  
  1041. In addition to setting the field width, the "width" function also returns the
  1042. value of the width just prior to the function call. If you wish to return this
  1043. value and leave it alone, then call the  width  function with no argument
  1044. specified.
  1045.  
  1046. IMPORTANT NOTE: Under the current implementation of Turbo C++,
  1047. the field width specification does NOT apply to character fields that are
  1048. output. This does not mean that the width reverts back to zero upon
  1049. encountering a character field, but instead is applied to the next non-
  1050. character field that is encountered. The patch IOPAT.ZIP in the
  1051. CompuServe BPROGB forum will fix this problem.
  1052.  
  1053. ******************************************************************
  1054. Specifying the Fill Character
  1055.  
  1056. If the total number of characters needed to display a field is less than the
  1057. current field width, the extra output spaces will be filled with the current
  1058. fill character. In a "printf" function call, the default fill character is a
  1059. blank, and you only have the option to change it to a zero.
  1060.  
  1061. In C++, however, you now have the option for any character to serve as the
  1062. fill character. As before, the default is a blank. The member function "fill"
  1063. is used to specify a new fill character. Once it is specified, it remains as
  1064. the fill character unless it is subsequently changed. The function takes a
  1065. single argument: the new fill character, and returns the previous fill
  1066. character. As with "width", it may be called with no actual argument if you
  1067. merely want to return the previous fill character.
  1068.  
  1069. This example outputs the default fill character, changes it to an asterisk, and
  1070. then proves that the current fill character is, indeed, an asterisk.
  1071.  
  1072.  // EXAMPLE OUTPUT-51
  1073.  
  1074.  // HOW TO SET THE FILL CHARACTER
  1075.  
  1076.  #include <header.h>
  1077.  
  1078.  int main()
  1079.  {
  1080.     const char quote = '\'' ;
  1081.     char old_fill = cout.fill('*') ;
  1082.     cout << "Old fill character is "
  1083.          << quote
  1084.          << old_fill
  1085.          << quote
  1086.          << '\n' ;
  1087.  
  1088.     cout << "It was changed to "
  1089.          << quote
  1090.          << cout.fill()
  1091.          << quote
  1092.          << '\n' ;
  1093.  
  1094.     return 0 ;
  1095.  }
  1096.  
  1097. The output of this program is:
  1098.  
  1099. Old fill character is ' '
  1100. It was changed to '*'
  1101.  
  1102. Now let's re-run example OUTPUT-41, but this time we'll fill the first
  1103. field with zeroes, and the second with asterisks.
  1104.  
  1105.  // EXAMPLE OUTPUT-52
  1106.  
  1107.  // A COMBINATION OF SETTING THE
  1108.  // FIELD WIDTH AND SPECIFYING
  1109.  // THE FILL CHARACTER
  1110.  
  1111.  #include <header.h>
  1112.  
  1113.  int main()
  1114.  {
  1115.     cout.width(5) ;
  1116.     cout.fill('0') ;
  1117.     cout << 1 << '\n' ;
  1118.     cout.width(5) ;
  1119.     cout.fill('*') ;
  1120.     cout << 23 << '\n' ;
  1121.  
  1122.     return 0 ;
  1123.  }
  1124.  
  1125. The output of this program is:
  1126.  
  1127. 00001
  1128. ***23
  1129.  
  1130. ******************************************************************
  1131. Field Justification
  1132.  
  1133. Whenever a field gets output, and the field width is greater than the number
  1134. of characters needed to display the field, the data is always right-justified
  1135. with the fill character used as padding to the left. (Of course, if the field
  1136. width is less than or equal to the number of characters needed, no
  1137. justification occurs and the fill character is ignored.)
  1138.  
  1139. Recall that there are 3 bits which are used to set the field justification:
  1140.  
  1141.  ios::left      0x0002     Left-justification of output
  1142.  ios::right     0x0004     Right-justification of output
  1143.  ios::internal  0x0008     Pad after sign or base indicator
  1144.  
  1145. If no bit is set in the field "x_flags", then the justification defaults to
  1146. right. Once the justification has been set, it remains set unless it is sub-
  1147. sequently changed. As with setting the base, there is a field called
  1148. "ios::adjustfield" which has been defined with all 3 justification bits turned
  1149. on. When setting the justification, this field should be used as the second
  1150. argument in the "setf" member function call to ensure that the other 2 bits are
  1151. turned off. To set the justification to left, use the member function "setf"
  1152. with the bit "ios::left", and to change it back to right, use the bit
  1153. "ios::right".
  1154.  
  1155. Here is example OUTPUT-41 again, this time with both fields left-justified.
  1156.  
  1157.  // EXAMPLE OUTPUT-60
  1158.  
  1159.  // HOW TO LEFT-JUSTIFY A FIELD
  1160.  
  1161.  #include <header.h>
  1162.  
  1163.  int main()
  1164.  {
  1165.     cout.setf(ios::left , ios::adjustfield) ;
  1166.     cout.width(5) ;
  1167.     cout.fill('0') ;
  1168.     cout << 1 << '\n' ;
  1169.     cout.width(5) ;
  1170.     cout.fill('*') ;
  1171.     cout << 23 << '\n' ;
  1172.  
  1173.     return 0 ;
  1174.  }
  1175.  
  1176. The output of this program is:
  1177.  
  1178. 10000
  1179. 23***
  1180.  
  1181. The justification resulting from the "ios::internal" bit means that padding
  1182. with the fill character, if any, will occur after the base of the number has
  1183. been shown (for octal and hexadecimal numbers) and before the number
  1184. itself. In the case of decimal numbers, the padding will occur after the sign
  1185. ('+' or '-') and before the number itself. That is, instead of padding
  1186. occurring on the left or on the right, it occurs "in the middle".
  1187.  
  1188. In this example, the base is shown, the fill character is set to '=', the
  1189. internal  bit is set on, the field width is set to 10, hexadecimal output is
  1190. requested, and the number 65 is printed. Then the same number is printed
  1191. again, but with left justification.
  1192.  
  1193.  // EXAMPLE OUTPUT-61
  1194.  
  1195.  // HOW TO DO INTERNAL JUSTIFICATION
  1196.  
  1197.  #include <header.h>
  1198.  
  1199.  int main()
  1200.  {
  1201.     cout.setf(ios::showbase) ;
  1202.     cout.fill('=') ;
  1203.     cout.setf(ios::internal , ios::adjustfield) ;
  1204.     cout.width(10) ;
  1205.     cout.setf(ios::hex , ios::basefield) ;
  1206.     cout << 65 << '\n' ;
  1207.     cout.setf(ios::left , ios::adjustfield) ;
  1208.     cout.width(10) ;
  1209.     cout << 65 << '\n' ;
  1210.  
  1211.     return 0 ;
  1212.  }
  1213.  
  1214.  The output of this program is:
  1215.  
  1216. 0x======41
  1217. 0x41======
  1218.  
  1219. ******************************************************************
  1220. Floating Point Output
  1221.  
  1222. Floating point numbers are output in C++ just like any other type of
  1223. number. However, the formatting is certainly different, and default values
  1224. are not the same as you would get from using a "printf" function call.
  1225.  
  1226. In this example some floating point constants are output.
  1227.  
  1228.  // EXAMPLE OUTPUT-70
  1229.  
  1230.  // DISPLAY SOME FLOATING POINTS
  1231.  // CONSTANTS WITHOUT ANY FORMATTING
  1232.  
  1233.  #include <header.h>
  1234.  
  1235.  int main()
  1236.  {
  1237.     cout << 1.2300 << '\n' ;
  1238.     cout << 4.00 << '\n' ;
  1239.     cout << 5.678E2 << '\n' ;
  1240.     cout << 0.0 << '\n' ;
  1241.  }
  1242.  
  1243. The output of this program is:
  1244.  
  1245. 1.23
  1246. 4
  1247. 567.8
  1248. 0
  1249.  
  1250. For the first constant, note that the 2 trailing zeroes were not printed. This
  1251. is certainly different from "printf" in which the default is to show 6
  1252. positions after the decimal point. In the second case, not only do the trailing
  1253. zeroes  not  show, but even the decimal point does not appear. In the third
  1254. case, the number prints in fixed point notation despite being keyed in
  1255. scientific notation. In the final case, at least one significant digit will
  1256. always appear.
  1257.  
  1258. Thus, we can infer that by default, all trailing zeroes, even the decimal
  1259. point, will be suppressed. If you really want to emulate how the "printf"
  1260. function works, you need to turn on the "ios::showpoint" bit. To revert
  1261. back to the default value, use the function "unsetf" to turn it off. Here is
  1262. the same example with this bit now on in the field "x_flags".
  1263.  
  1264.  // EXAMPLE OUTPUT-71
  1265.  
  1266.  // HOW TO EMULATE printf
  1267.  
  1268.  #include <header.h>
  1269.  
  1270.  int main()
  1271.  {
  1272.     cout.setf(ios::showpoint) ;
  1273.     cout << 1.2300 << '\n' ;
  1274.     cout << 4.00 << '\n' ;
  1275.     cout << 5.678E2 << '\n' ;
  1276.     cout << 0.0 << '\n' ;
  1277.  
  1278.     return 0 ;
  1279.  }
  1280.  
  1281. The output of this program is:
  1282.  
  1283. 1.230000
  1284. 4.000000
  1285. 567.800000
  1286. 0.000000
  1287.  
  1288. The next step is to override the default of 6 decimal positions. To do this,
  1289. use the member function "precision" in which the one argument is the
  1290. number of decimal positions to be shown. This function also returns the
  1291. previous value of the precision. If it is called without an argument, it
  1292. merely returns the current value of the precision and does not alter it. The
  1293. default precision is 0.
  1294.  
  1295. Here is the same example with the precision now set to 1.
  1296.  
  1297.  // EXAMPLE OUTPUT-72
  1298.  
  1299.  // HOW TO EMULATE printf AND SET
  1300.  // THE PRECISION
  1301.  
  1302.  #include <header.h>
  1303.  
  1304.  int main()
  1305.  {
  1306.     cout.setf(ios::showpoint) ;
  1307.     cout.precision(1) ;
  1308.     cout << 1.2300 << '\n' ;
  1309.     cout << 4.00 << '\n' ;
  1310.     cout << 5.678E2 << '\n' ;
  1311.     cout << 0.0 << '\n' ;
  1312.  
  1313.     return 0 ;
  1314.  }
  1315.  
  1316. The output of this program is:
  1317.  
  1318. 1.2
  1319. 4.0
  1320. 5.7e+02
  1321. 0.0
  1322.  
  1323. Note that the third answer is displayed in scientific notation. To guarantee
  1324. that all output is shown in either fixed decimal or scientific notation, recall
  1325. that the following bits are pre-defined in the class "ios":
  1326.  
  1327.    ios::scientific     0x0800    Use exponential notation on floating
  1328.                                  point numbers
  1329.    ios::fixed          0x1000    Use fixed decimal output on floating point
  1330.                                  numbers
  1331.  
  1332. If neither bit is turned on, then the compiler emulates the "%g" conversion
  1333. specification in a "printf" function call. Also recall that there is a constant
  1334. called "ios:floatfield" that is the value of these two bits ORed together, and
  1335. may be used as the second argument in a "setf" function call.
  1336.  
  1337.  // EXAMPLE OUTPUT-73
  1338.  
  1339.  // HOW TO EMULATE printf AND SET
  1340.  // THE PRECISION
  1341.  
  1342.  #include <header.h>
  1343.  
  1344.  int main()
  1345.  {
  1346.     cout.setf(ios::showpoint) ;
  1347.     cout.precision(2) ;
  1348.  
  1349.     // Guarantee fixed decimal
  1350.     cout.setf(ios::fixed , ios::floatfield) ;
  1351.     cout << 1.2300 << '\n' ;
  1352.     cout << 4.00 << '\n' ;
  1353.     cout << 5.678E2  << '\n' ;
  1354.     cout << 0.0 << '\n' ;
  1355.  
  1356.     // Guarantee scientific
  1357.     cout.setf(ios::scientific , ios::floatfield) ;
  1358.     cout << 1.2300 << '\n' ;
  1359.     cout << 4.00  << '\n' ;
  1360.     cout << 5.678E2<< '\n' ;
  1361.     cout << 0.0 << '\n' ;
  1362.  
  1363.     return 0 ;
  1364.  }
  1365.  
  1366. The output of this program is:
  1367.  
  1368. 1.23
  1369. 4.00
  1370. 567.80
  1371. 0.00
  1372. 1.23e+00
  1373. 4.00e+00
  1374. 5.68e+02
  1375. 0.00e+00
  1376.  
  1377. ******************************************************************
  1378. Printing addresses
  1379.  
  1380. The address of a variable (or instance of a class) can be generated by using
  1381. the address operator (&). Because the address operator can be applied to a
  1382. wide variety of types (both built-in and user-defined), the type of argument
  1383. can theoretically be "pointer to int" or "pointer to float" or even 'pointer to
  1384. my class type'. To accommodate all of these various types, the class
  1385. "ostream" contains an overloaded function "operator<<" to handle all such
  1386. argument types. This function is prototyped to accept an argument of type
  1387. "void*" which, according to the rules of argument matching, is acceptable to
  1388. the compiler as a "match".
  1389.  
  1390. In Turbo C++, this address is always shown in 32-bit (4 byte) hexadecimal
  1391. form, even though the default output base is decimal .
  1392.  
  1393.  // EXAMPLE OUTPUT-80
  1394.  
  1395.  // HOW TO PRINT AN ADDRESS
  1396.  
  1397.  #include <header.h>
  1398.  
  1399.  int main()
  1400.  {
  1401.     int number ;
  1402.  
  1403.     cout << "Address of number as a\n"
  1404.          << "  32-bit hex is "
  1405.          << &number
  1406.          << '\n' ;
  1407.  
  1408.     return 0 ;
  1409.  }
  1410.  
  1411. If you wish, you may view this address in decimal by using a cast to an
  1412. unsigned long.
  1413.  
  1414.  // EXAMPLE OUTPUT-81
  1415.  
  1416.  // HOW TO PRINT AN ADDRESS IN
  1417.  // DECIMAL AS AN UNSIGNED LONG
  1418.  
  1419.  #include <header.h>
  1420.  
  1421.  int main()
  1422.  {
  1423.     int number ;
  1424.  
  1425.     cout << "Address of number as a\n"
  1426.          << "  long integer is "
  1427.          << (unsigned long)&number
  1428.          << '\n' ;
  1429.  
  1430.     return 0 ;
  1431.  }
  1432.  
  1433. But since addresses are stored in 2 bytes when using the small memory
  1434. model, it's probably better to cast to an "unsigned int".
  1435.  
  1436.  // EXAMPLE OUTPUT-82
  1437.  
  1438.  // HOW TO PRINT AN ADDRESS IN
  1439.  // DECIMAL AS AN UNSIGNED INT
  1440.  
  1441.  #include <header.h>
  1442.  
  1443.  int main()
  1444.  {
  1445.     int number ;
  1446.  
  1447.      cout << "Address of number as an\n"
  1448.           << "  unsigned int is "
  1449.           << (unsigned)&number
  1450.           << '\n' ;
  1451.  
  1452.     return 0 ;
  1453.  }
  1454.  
  1455. When dealing with a string, a problem arises. It's the same problem that
  1456. occurred in C in a program fragment such as:
  1457.  
  1458.   char* ptr = "ABC" ;
  1459.   printf ("%s" , ptr) ;
  1460.  
  1461. No doubt the user will see "ABC" as the output. The problem is how to print
  1462. the ADDRESS contained within the pointer variable "ptr". The solution in C is
  1463. to provide a different conversion specification, namely "%p".
  1464.  
  1465. In C++ this program fragment:
  1466.  
  1467.   char* ptr = "ABC" ;
  1468.   cout << ptr ;
  1469.  
  1470. would also output "ABC" because the argument "ptr" is of type "char*" which
  1471. matches exactly an overloaded "operator<<" that accepts an argument of
  1472. type "char*". To emulate the "%p" in C++, you must override the built-in
  1473. type of "char*" with the type "void*" so that the "operator<<" function that
  1474. outputs an ADDRESS will be called instead.
  1475.  
  1476.  // EXAMPLE OUTPUT-83
  1477.  
  1478.  // HOW TO PRINT AN ADDRESS OF
  1479.  // A STRING
  1480.  
  1481.  #include <header.h>
  1482.  
  1483.  int main()
  1484.  {
  1485.     char* ptr = "ABC" ;
  1486.  
  1487.     cout << "The string itself is "
  1488.          << ptr
  1489.          << '\n' ;
  1490.  
  1491.     cout << "The address of the"
  1492.          << "string is "
  1493.          << (unsigned)(void*)ptr
  1494.          << '\n' ;
  1495.  
  1496.     return 0 ;
  1497.  }
  1498.  
  1499. ******************************************************************
  1500. Binary output
  1501.  
  1502. It's possible to take any internal representation of a C++ type and output it
  1503. as though it were just an array of characters. For a type such as "float", this
  1504. will produce meaningless output, but it may be useful for integers. To do
  1505. this, the member function  write  must be used. This function takes 2
  1506. arguments: The first is the address of the data to be output, and the second
  1507. is the number of bytes to be shown. Note that in the case of a string, the
  1508. null byte is treated just like any other byte.
  1509.  
  1510. Because the function "write" is declared to accept an argument of type
  1511. "char*", if the item you wish to print is not of this type, then the address
  1512. must be generated using the address operator, and then cast to type "char*".
  1513.  
  1514.  // EXAMPLE OUTPUT-90
  1515.  
  1516.  // HOW TO DISPLAY THE BINARY REPRE-
  1517.  // SENTATION OF A NUMBER
  1518.  
  1519.  #include <header.h>
  1520.  
  1521.  int main()
  1522.  {
  1523.     long number = 0x414243 ;
  1524.  
  1525.     cout.write((char*)&number , sizeof(number)) ;
  1526.     cout << '\n' ;
  1527.  
  1528.     return 0 ;
  1529.  }
  1530.  
  1531. Note that the output of this program is "CBA", because the address of a "long"
  1532. refers to the low-order byte.
  1533.  
  1534. ************************ SECTION 3 -- INPUT *********************************
  1535.  
  1536. Introduction
  1537.  
  1538. In addition to being able to use classes to control output, C++ stream I/O
  1539. classes also handle all input. Just as output consists of a stream of characters
  1540. being sent to some device, input consists of characters coming in from some
  1541. device and being translated into their proper defined type. In other words,
  1542. the characters '1', '2' and '3' could be the string '123' or the integer 123,
  1543. depending upon the type of the receiving field. Unlike output, the realm of
  1544. possibilities for 'formatting' simply does not exist when inputting data.
  1545.  
  1546. The class "istream" is derived from the class "ios", and it controls the input
  1547. handling functions. The global instance that is defined for you is called "cin",
  1548. and is defined as:
  1549.  
  1550.    istream cin ;
  1551.  
  1552. In addition to data members, the class "istream" contains functions to
  1553. operate upon these members. The function you will use the most often is
  1554. called the extraction operator, and it is written as:
  1555.  
  1556.    operator>>
  1557.  
  1558. The argument to this function is the variable name that you wish to contain
  1559. the input. The name 'extraction' comes from the fact that you are
  1560. 'extracting' (taking) data from the input stream.
  1561.  
  1562. For example, to input an integer, you would code:
  1563.  
  1564.    int number ;
  1565.    cin.operator>>(number) ;
  1566.  
  1567. As with the insertion operator, this code can be replaced with the simpler
  1568. form:
  1569.  
  1570.    int number ;
  1571.    cin >> number ;
  1572.  
  1573. Note that the type of the input variable determines how the characters from
  1574. the input stream are to be stored.
  1575.  
  1576. For example, this program inputs a number, character and float, and then
  1577. echoes them back.
  1578.  
  1579.  // EXAMPLE INPUT-01
  1580.  
  1581.  // HOW TO INPUT SOME SIMPLE TYPES
  1582.  
  1583.  #include <header.h>
  1584.  
  1585.  int main()
  1586.  {
  1587.     int number ;
  1588.     cout << "Enter a number: " ;
  1589.     cin >> number ;
  1590.     cout << "You entered: "
  1591.          << number
  1592.          << '\n' ;
  1593.  
  1594.     char ch ;
  1595.     cout << "Enter a character: " ;
  1596.     cin >> ch ;
  1597.     cout << "You entered: "
  1598.          << ch
  1599.          << '\n' ;
  1600.  
  1601.     float fl ;
  1602.     cout << "Enter a float: " ;
  1603.     cin >> fl ;
  1604.     cout << "You entered: "
  1605.          << fl
  1606.          << '\n' ;
  1607.  
  1608.     return 0 ;
  1609.  }
  1610.  
  1611. The extraction operator, like the insertion operator, can be chained
  1612. together.
  1613.  
  1614.  // EXAMPLE INPUT-02
  1615.  
  1616.  // EXTRACTION OPERATORS CAN BE
  1617.  // CHAINED TOGETHER
  1618.  
  1619.  #include <header.h>
  1620.  
  1621.  int main()
  1622.  {
  1623.     int number1 , number2 ;
  1624.     cout << "Enter 2 numbers: " ;
  1625.     cin >> number1 >> number2 ;
  1626.     cout << "You entered: "
  1627.          << number1
  1628.          << " and "
  1629.          << number2
  1630.          << '\n' ;
  1631.  
  1632.     return 0 ;
  1633.  }
  1634.  
  1635. Recall from the discussion on output that numbers can be displayed in
  1636. either their decimal, octal, or hexadecimal representations. This is done by
  1637. changing the base setting of the output stream. In a similar fashion, the base
  1638. of the input stream can be changed from its default setting of decimal to
  1639. either octal or hexadecimal. This is how the "%o" and "%x" conversion
  1640. specifications in a "scanf" function call can be emulated. For example, this
  1641. program prompts the user for numbers in decimal, octal, and hexadecimal
  1642. formats, then echoes each number back. Note that the output is always in
  1643. decimal because the setting of the output base has not been affected. In
  1644. other words, the base setting is stored separately for each stream.
  1645. Obviously, if an illegal input value is entered, the value will not be stored.
  1646. (NOTE: Borland Turbo C++ version 1.00 had a bug in regard to the
  1647. inputting of octal and hex numbers, but it was corrected in version 1.01.)
  1648.  
  1649.  // EXAMPLE INPUT-03
  1650.  
  1651.  // INTEGERS CAN BE INPUT IN ANY OF
  1652.  // 3 DIFFERENT BASES
  1653.  
  1654.  #include <header.h>
  1655.  
  1656.  int main()
  1657.  {
  1658.     int number ;
  1659.  
  1660.     cout << "Enter a decimal number: " ;
  1661.     cin >> number ;
  1662.     cout << "You entered: "
  1663.          << number
  1664.          << endl ;
  1665.  
  1666.     cout << "Enter an octal number: " ;
  1667.     cin.setf(ios::oct , ios::basefield) ;
  1668.     cin >> number ;
  1669.     cout << "You entered: "
  1670.          << number
  1671.          << endl ;
  1672.  
  1673.     cout << "Enter a hex number: " ;
  1674.     cin.setf(ios::hex , ios::basefield) ;
  1675.     cin >> number ;
  1676.     cout << "You entered: "
  1677.          << number
  1678.          << endl ;
  1679.  
  1680.     return 0 ;
  1681.  }
  1682.  
  1683. If the operator enters 65 for all 3 prompts, then the output of this program
  1684. is:
  1685.  
  1686. 65
  1687. 53
  1688. 101
  1689.  
  1690. *****************************************************************
  1691. Character Input
  1692.  
  1693. Characters may be read in using either the extraction operator ">>" or the
  1694. member function "get" (think of the C function "getchar"). If the extraction
  1695. operator is used, then leading whitespace is bypassed and the first non-
  1696. whitespace character is fetched. Also, a reference to the invoking instance is
  1697. returned. In this example, enter some spaces and tabs before striking a
  1698. character and <RETURN>.
  1699.  
  1700.  // EXAMPLE INPUT-11
  1701.  
  1702.  // DEMONSTRATE HOW TO READ IN A
  1703.  // CHARACTER AND BYPASS LEADING
  1704.  // WHITESPACE
  1705.  
  1706.  #include <header.h>
  1707.  
  1708.  int main()
  1709.  {
  1710.     const char quote = '\'' ;
  1711.  
  1712.     cout << "Enter a character: " ;
  1713.     char ch ;
  1714.     cin >> ch ;
  1715.     cout << "You entered: "
  1716.          << quote
  1717.          << ch
  1718.          << quote
  1719.          << '\n' ;
  1720.  
  1721.     return 0 ;
  1722.  }
  1723.  
  1724. Another method to read a character is to use the member function "get". This
  1725. can be done in two differenct ways. The first takes one argument: the
  1726. character variable name pass in by reference. It returns a reference to the
  1727. invoking instance. The difference between the extraction operator ">>" and
  1728. "get" is that "get" does not use the format flags, so it does not bypass
  1729. leading whitespace. In this example, enter some spaces and then another
  1730. character. You will see that the first space gets entered into the variable.
  1731.  
  1732.  // EXAMPLE INPUT-12
  1733.  
  1734.  // DEMONSTRATE HOW TO READ IN A
  1735.  // CHARACTER AND RETAIN LEADING
  1736.  // WHITESPACE USING get(char&)
  1737.  
  1738.  #include <header.h>
  1739.  
  1740.  int main()
  1741.  {
  1742.     const char quote = '\'' ;
  1743.  
  1744.     cout << "Enter a character: " ;
  1745.     char ch ;
  1746.     cin.get(ch) ;
  1747.     cout << "You entered: "
  1748.          << quote
  1749.          << ch
  1750.          << quote
  1751.          << '\n' ;
  1752.  
  1753.     return 0 ;
  1754.  }
  1755.  
  1756. The other function using "get" takes no input argument (just like "getchar" in
  1757. C) and returns a value of type "int", which represents the character just read,
  1758. or the "EOF" constant if either (a) end-of-file was detected, or (b) no
  1759. character could be read. This function is unique in that it does not set
  1760. 'failbit'. The other unformatted extractors will set 'failbit' if called at
  1761. end-of-file time, so that no other characters can be read.
  1762.  
  1763. Here is example INPUT-12 repeated, but now it uses "get()" and checks for
  1764. end-of-file. Because the variable "ch" must be defined as type "int", don't
  1765. forget the cast in order to display it as a character.
  1766.  
  1767.  // EXAMPLE INPUT-13
  1768.  
  1769.  // DEMONSTRATE HOW TO READ IN A
  1770.  // CHARACTER AND RETAIN LEADING
  1771.  // WHITESPACE USING get()
  1772.  
  1773.  #include <header.h>
  1774.  
  1775.  int main()
  1776.  {
  1777.     const char quote = '\'' ;
  1778.  
  1779.     cout << "Enter a character: " ;
  1780.     int ch ;
  1781.     ch = cin.get() ;
  1782.     if (ch != EOF)
  1783.        cout << "You entered: "
  1784.             << quote
  1785.             << (char)ch
  1786.             << quote
  1787.             << '\n' ;
  1788.     else
  1789.        cout << "End-of-file\n" ;
  1790.  
  1791.     return 0 ;
  1792.  }
  1793.  
  1794. ******************************************************************
  1795. String Input
  1796.  
  1797. As with character input, strings may be entered using the extraction
  1798. operator or the overloaded member function "get". With the extraction
  1799. operator, leading whitespace is bypassed, and the first whitespace
  1800. encountered terminates the input. (This acts just like the function "scanf".)
  1801.  
  1802.  // EXAMPLE INPUT-21
  1803.  
  1804.  // DEMONSTRATE HOW TO READ IN A
  1805.  // STRING AND BYPASS WHITESPACE
  1806.  // TOTALLY (LOOKS LIKE scanf)
  1807.  
  1808.  #include <header.h>
  1809.  
  1810.  const int length = 100 ;
  1811.  
  1812.  int main()
  1813.  {
  1814.     char string [length] ;
  1815.     const char quote = '\"' ;
  1816.  
  1817.     cout << "Enter a string: " ;
  1818.     cin >> string ;
  1819.     cout << "Your string: "
  1820.          << quote
  1821.          << string
  1822.          << quote
  1823.          << '\n' ;
  1824.  
  1825.     return 0 ;
  1826.  }
  1827.  
  1828. But just like "scanf", the possibility exists for a program hang or crash if
  1829. the operator enters more characters than can safely be accommodated by the
  1830. string array. In other words, run this program and enter more than 10
  1831. characters.
  1832.  
  1833.  // EXAMPLE INPUT-22
  1834.  
  1835.  // IT'S POSSIBLE TO OVERFLOW AN
  1836.  // ARRAY WHEN INPUTTING A STRING
  1837.  
  1838.  #include <header.h>
  1839.  
  1840.  const int max = 10 ;
  1841.  
  1842.  int main()
  1843.  {
  1844.     char array[max] ;
  1845.  
  1846.     cout << "Enter a string: " ;
  1847.     cin >> array ;
  1848.     cout << "You entered: "
  1849.          << array
  1850.          << '\n' ;
  1851.  
  1852.     return 0 ;
  1853.  }
  1854.  
  1855. If it didn't bomb, consider yourself lucky. To guard against this disaster,
  1856. you may set the width of the input stream to physically limit the number of
  1857. characters that will be stored. This is done by using the member function
  1858. "width" in the class "istream". Run this program and enter the letters 'A'
  1859. through 'M'. Note that only the letters 'A' through 'I' got stored into the
  1860. string (the last byte is always reserved for the null character) and the
  1861. remaining characters remain in the input buffer.
  1862.  
  1863.  // EXAMPLE INPUT-23
  1864.  
  1865.  // HOW TO AVOID OVERFLOWING AN
  1866.  // ARRAY WHEN INPUTTING A STRING
  1867.  // WITH THE EXTRACTION OPERATOR
  1868.  
  1869.  #include <header.h>
  1870.  
  1871.  const int max = 10 ;
  1872.  
  1873.  int main()
  1874.  {
  1875.     char array[max] ;
  1876.  
  1877.     cout << "Enter a string: " ;
  1878.     cin.width(max) ;
  1879.     cin >> array ;
  1880.     cout << "You entered: "
  1881.          << array
  1882.          << '\n' ;
  1883.  
  1884.     return 0 ;
  1885.  }
  1886.  
  1887. Caution: Just like the "width" function used for output, the input "width"
  1888. function only applies to the next item to be input.
  1889.  
  1890. Another way to read in strings is to use the member function  get  with 3
  1891. arguments. (Note the similarity to the C function "fgets".) The first
  1892. argument is the address of the string area, the second is the maximum
  1893. number of characters (less 1) than can be read in, and the third specifies the
  1894. terminating character (the one that will stop the transfer of characters from
  1895. the buffer into the string array). This third argument defaults to the value
  1896. '\n', which is the <RETURN> key. Note, however, that if it is changed to
  1897. some other character, then the <RETURN> key must still be pressed for
  1898. the input action to cease. Both leading whitespace and embedded
  1899. whitespace are retained as part of the string value.
  1900.  
  1901.  // EXAMPLE INPUT-24
  1902.  
  1903.  // DEMONSTRATE HOW TO READ IN A
  1904.  // STRING AND RETAIN WHITESPACE,
  1905.  // BOTH LEADING AND EMBEDDED
  1906.  
  1907.  #include <header.h>
  1908.  
  1909.  const int length = 100 ;
  1910.  
  1911.  int main()
  1912.  {
  1913.     char string [length] ;
  1914.     const char quote = '\"' ;
  1915.  
  1916.     cout << "Enter a string: " ;
  1917.     cin.get(string , length) ;
  1918.     cout << "Your string: "
  1919.          << quote
  1920.          << string
  1921.          << quote
  1922.          << '\n' ;
  1923.  
  1924.     return 0 ;
  1925.  }
  1926.  
  1927. A slight variation on the function "get" taking 3 arguments is the function
  1928. "getline". The only difference is that "getline" extracts the newline character
  1929. ('\n') from the input buffer, whereas "get" leaves it alone (and, presumably,
  1930. must then be flushed by the programmer). In Turbo C++ version 1.01, this
  1931. newline character is made part of the string, even though the A T & T spec
  1932. does not say to do this.
  1933.  
  1934.  // EXAMPLE INPUT-25
  1935.  
  1936.  // TEST getline FUNCTION
  1937.  
  1938.  // NOTE THAT THE LAST DOUBLE QUOTE
  1939.  // APPEARS ON THE FOLLOWING LINE
  1940.  // DUE TO THE INCLUSION OF THE
  1941.  // NEWLINE CHARACTER IN string
  1942.  
  1943.  #include <header.h>
  1944.  
  1945.  const int length = 100 ;
  1946.  
  1947.  int main()
  1948.  {
  1949.     char string [length] ;
  1950.     const char quote = '\"' ;
  1951.  
  1952.     cout << "Enter a string: " ;
  1953.     cin.getline(string , length) ;
  1954.     cout << "Your string: "
  1955.          << quote
  1956.          << string
  1957.          << quote ;
  1958.  
  1959.     return 0 ;
  1960.  }
  1961.  
  1962. ******************************************************************
  1963. Checking for End-Of-File
  1964.  
  1965. When reading data from the keyboard or a file, the programmer must
  1966. always be on guard for the occurrence of an end-of-file mark (in DOS it's
  1967. the character ^Z or decimal value 26 from text files). This is comparable to
  1968. detecting the value "EOF" when doing a "scanf" in C.
  1969.  
  1970. In C++, the member function "eof" in the class "istream" taking no arguments
  1971. will report 'true' if the end-of-file condition was found, 'false' if not
  1972. found.
  1973.  
  1974. Normally data is obtained within a 'while' loop, with the loop continuing to
  1975. execute as long as end-of-file is  not  detected. This situation could be coded
  1976. like this:
  1977.  
  1978.  // EXAMPLE INPUT-31
  1979.  
  1980.  // ENTER A NUMBER AND LOOP
  1981.  // UNTIL EOF IS DETECTED
  1982.  
  1983.  #include <header.h>
  1984.  
  1985.  int main()
  1986.  {
  1987.     cout << "Enter a number: " ;
  1988.     int num ;
  1989.     cin >> num ;
  1990.     while (!cin.eof())
  1991.     {
  1992.        cout << "You entered: "
  1993.             << num
  1994.             << '\n' ;
  1995.        cout << "\nNext number: " ;
  1996.        cin >> num ;
  1997.     }
  1998.  
  1999.     return 0 ;
  2000.  }
  2001.  
  2002. While this program certainly works, there is a better way to code it. Since
  2003. the statement:
  2004.  
  2005.    cin >> num ;
  2006.  
  2007. returns a reference to the invoking object itself (namely "cin"), this object
  2008. can be used as the invoking object for the "eof" member function call. Thus,
  2009. the revised code looks like:
  2010.  
  2011.  // EXAMPLE INPUT-32
  2012.  
  2013.  // A BETTER METHOD OF CODING
  2014.  // EXAMPLE INPUT-31
  2015.  
  2016.  #include <header.h>
  2017.  
  2018.  int main()
  2019.  {
  2020.     cout << "Enter a number: " ;
  2021.     int num ;
  2022.     while (!(cin >> num).eof())
  2023.     {
  2024.       cout << "You entered: "
  2025.            << num
  2026.            << '\n' ;
  2027.       cout << "\nNext number: " ;
  2028.     }
  2029.  
  2030.     return 0 ;
  2031.  }
  2032.  
  2033. Notice how the read and check for end-of-file have been combined to form
  2034. the Boolean condition of the 'while' loop.
  2035.  
  2036. ******************************************************************
  2037. Checking for Errors
  2038.  
  2039. Unfortunately, we live in an imperfect world. People don't smile, cars
  2040. crash, checks bounce, and data entry operators don't always do what they're
  2041. supposed to do. This means that as a programmer you must be responsible
  2042. for making your code as 'operator-proof' as possible. In other words, no
  2043. matter what the user may enter as 'data', your program must capture it and
  2044. successfully trap all error conditions to avoid such catastrophes as 'garbage
  2045. in, garbage out', aborts, hangs, endless loops, etc.
  2046.  
  2047. When expecting character or string input, there's not too much that can go
  2048. wrong, other than array overflow which has already been covered. But
  2049. with numeric data, such as "int"s, "float"s and "double"s, only certain
  2050. keystrokes in a prescribed order and considered to be valid. For example,
  2051. when you expect a decimal integer to be input, the user may enter a sign (+
  2052. or -) followed by the digits 0 through 9. An entry of A12 is obviously
  2053. invalid. An entry such as 12A, however, is considered to be the number 12,
  2054. with the "invalid" character 'A' serving to terminate the numeric portion of
  2055. the input stream. In addition, any whitespace character terminates a
  2056. numeric entry, and all leading whitespace characters are bypassed
  2057. automatically.
  2058.  
  2059. There are several ways to check for 'garbage' input when expecting valid
  2060. numeric data. Within the class "istream" the member function "good" will
  2061. return 'true' if the preceding operation succeeded, 'false' otherwise. In
  2062. addition, the member function "fail" will do just the opposite.
  2063.  
  2064. Another way to check for an input error is to use the overloaded "operator!"
  2065. (Boolean not) on the instance of "istream". This operator will return
  2066. 'true' if an error occurred, 'false' otherwise. Similarly, testing the
  2067. instance itself as a Boolean value will return 'true' if the input was good,
  2068. 'false' otherwise.
  2069.  
  2070. Note that in the header file <header.h> the function "IOFLAGS" has been
  2071. defined to accept an instance of an input stream as an argument, and will
  2072. display the various input states. The default argument is the instance "cin".
  2073. To test this, trying entering some numeric and non-numeric data for this
  2074. program, as well as end-of-file.
  2075.  
  2076.  // EXAMPLE INPUT-41
  2077.  
  2078.  // TEST THE INPUT STREAM STATES
  2079.  
  2080.  #include <header.h>
  2081.  
  2082.  int main()
  2083.  {
  2084.     cout << "Enter a number: " ;
  2085.     int number ;
  2086.     cin >> number ;
  2087.     IOFLAGS() ;
  2088.  
  2089.     return 0 ;
  2090.  }
  2091.  
  2092. Now that you see what does and does not work, the next problem is how to
  2093. eliminate the excess, or garbage, characters from the input stream. This can
  2094. be accomplished by reading 1 character at a time until the <RETURN>
  2095. ('\n') character has been read. (Of course this method assumes that if an
  2096. error condition is encountered, then the integrity of the remaining
  2097. characters in the buffer is in question.) In addition, when an error occurs,
  2098. the status of the input stream is changed from 'good' to 'fail' and  no more
  2099. characters can be read until the status is reset to 'good' . To do this, you
  2100. must call upon the "istream" member function "clear" with no arguments (the
  2101. default argument is 0, which means 'set the status of the stream to 'good'').
  2102.  
  2103. To save you the trouble of having to code a function to accomplish this
  2104. 'flushing' task, the file <header.h> has a manipulator called FLUSH that will
  2105. do this for you. (The subject of manipulators and how they work will be
  2106. covered in the section on manipulators.)
  2107.  
  2108. Thus, an 'operator-proof' program that loops while reading numbers and
  2109. checking for end-of-file and garbage input might resemble this:
  2110.  
  2111.  // EXAMPLE INPUT-42
  2112.  
  2113.  // SHOW HOW TO HANDLE ANYTHING
  2114.  // THE OPERATOR CAN THROW AT
  2115.  // THE PROGRAM
  2116.  
  2117.  #include <header.h>
  2118.  
  2119.  int main()
  2120.  {
  2121.     cout << "\nEnter a number: " ;
  2122.     int number ;
  2123.     while (!(cin >> number).eof())
  2124.     {
  2125.       // Test for a bad number
  2126.       if (!cin)
  2127.         cout << "Input error!\n" ;
  2128.  
  2129.       // Process a good number
  2130.       else
  2131.         cout << "YOU ENTERED: "
  2132.              << number
  2133.              << endl ;
  2134.  
  2135.       // Clear out the input buffer.
  2136.       cin >> FLUSH ;
  2137.  
  2138.       cout << "\nNext number: " ;
  2139.     }
  2140.     cout << "\nEND OF PROGRAM\n" ;
  2141.  
  2142.     return 0 ;
  2143.  }
  2144.  
  2145. One note about the logic of this program. If 2 valid numbers are entered
  2146. before the user presses <RETURN>, then only the first number will be
  2147. processed; the second will be flushed. You may or may not want this to
  2148. happen, depending upon your design philosophy.
  2149.  
  2150. ************************ SECTION 4 -- MANIPULATORS ************************
  2151.  
  2152. Introduction
  2153.  
  2154. As you have probably noticed by now, the elimination of conversion
  2155. specifications ("%d", "%c", etc.) found in the "scanf" and "printf" functions
  2156. in C causes you to do a lot of extra coding to accomplish the same end result.
  2157. For example, to output a number in hex, the specification "%x" does the job
  2158. in a "printf" statement, but with <iostream.h> you have to write:
  2159.  
  2160.   cout.setf(ios::hex , ios::basefield) ;
  2161.  
  2162. before outputting the number itself.
  2163.  
  2164. Fortunately, the input and output stream classes provide the capability to
  2165. eliminate much of this tedious coding, as well as a method to combine the
  2166. setting of the stream state with the actual outputting (or inputting) of the
  2167. data itself. This method uses what is called a 'manipulator'. The term
  2168. comes from the fact that a manipulator does just what it implies: it
  2169. manipulates, or changes, the state of the stream.
  2170.  
  2171. In the same sense that a call of a function causes that function to do any
  2172. number of individual tasks the programmer may specify, a manipulator is
  2173. also a function that sets the stream state. The input and output classes come
  2174. with some manipulators already built in, and a nice feature is that you can
  2175. easily define your own.
  2176.  
  2177. The one peculiar aspect about manipulators is that they are always called
  2178. 'indirectly' by a separate function. This other function knows which
  2179. individual manipulator to call because it has the manipulator's  address  as
  2180. its one argument. How does it get this address? When the name of a function is
  2181. written without the open and close parentheses, the compiler generates the
  2182. address  of the function instead of actually calling the function. This address
  2183. can, in turn, be passed as an argument to another function. Of course, this
  2184. address must be stored into a variable declared as 'pointer to function' and
  2185. which has the proper return type and argument list.
  2186.  
  2187. In this example the address of the function "print" is passed as an argument
  2188. to the function called "test", stored into the pointer variable called "ptr",
  2189. and then executed via the statement "ptr();". Note that this is the same as
  2190. coding (*ptr)();
  2191.  
  2192.  // EXAMPLE MANIP-01
  2193.  
  2194.  // HOW TO PASS THE ADDRESS OF A
  2195.  // FUNCTION AS AN ARGUMENT
  2196.  
  2197.  #include <header.h>
  2198.  
  2199.  // Function declarations
  2200.  
  2201.  void print() ;
  2202.  void test(void (*)()) ;
  2203.  
  2204.  int main()
  2205.  {
  2206.     test(print) ;
  2207.  
  2208.     return 0 ;
  2209.  }
  2210.  
  2211.  void print()
  2212.  {
  2213.     cout << "print function\n" ;
  2214.  }
  2215.  
  2216.  void test(void (*ptr)())
  2217.  {
  2218.     ptr() ;
  2219.  }
  2220.  
  2221. Since the manipulators to handle input and output stream states can be
  2222. chained with other arguments, then (assuming output) generically they have
  2223. the form:
  2224.  
  2225.   cout << data-item1 << manipulator << data-item2 ;
  2226.  
  2227. In order to preserve the ability to concatenate successive calls to the
  2228. insertion operator function, each manipulator function must adhere to the
  2229. rule that the invoking instance is always passed in by reference and
  2230. returned by reference. This means that all manipulator functions have the
  2231. format:
  2232.  
  2233.  ostream& manipulator_name(ostream& strm)
  2234.  {
  2235.    // your code here
  2236.   return strm ;
  2237.  }
  2238.  
  2239. In a similar fashion, all input manipulators have the format:
  2240.  
  2241.  istream& manipulator_name(istream& strm)
  2242.  {
  2243.    // your code here
  2244.   return strm ;
  2245.  }
  2246.  
  2247. To accommodate an argument of type 'pointer to function', the class
  2248. "ostream" has an overloaded insertion operator similar to this:
  2249.  
  2250.  ostream& operator<<(ostream& (*ptr)(ostream&))
  2251.  {
  2252.   return (*ptr)(*this) ;
  2253.  }
  2254.  
  2255.  The class  istream  has an overloaded insertion operator similar to this:
  2256.  
  2257.  istream& operator<<(istream& (*ptr)(istream&))
  2258.  {
  2259.   return (*ptr)(*this) ;
  2260.  }
  2261.  
  2262. It's these two functions that call upon your manipulator function whose
  2263. address has been stored into the pointer variable "ptr".
  2264.  
  2265. As a test, here is a program that creates a manipulator function called
  2266. "manip" that sets the field width to 5 and the fill character to '*'.
  2267.  
  2268.  // EXAMPLE MANIP-02
  2269.  
  2270.  // HOW TO PASS CREATE YOUR OWN
  2271.  // MANIPULATOR
  2272.  
  2273.  #include <header.h>
  2274.  
  2275.  ostream& manip(ostream& strm)
  2276.  {
  2277.     strm.width(5) ;
  2278.     strm.fill('*') ;
  2279.     return strm ;
  2280.  }
  2281.  
  2282.  int main()
  2283.  {
  2284.     cout << manip
  2285.          << 23
  2286.          << '\n' ;
  2287.  
  2288.     return 0 ;
  2289.  }
  2290.  
  2291. The output of this program is:
  2292.  
  2293. ***23
  2294.  
  2295. ******************************************************************
  2296. Built-in Manipulators Taking No Arguments
  2297.  
  2298. Because some output (and input) stream manipulations are done so
  2299. frequently, the header file <iostream.h> includes some pre-defined
  2300. manipulators. These manipulators may take no arguments, or 1 argument.
  2301. Let's first consider some built-in manipulators that take no arguments.
  2302.  
  2303. As the first example, the manipulator "endl" is designed to output a new line
  2304. character and flush the output buffer. Use may use this in place of '\n'. For
  2305. example,
  2306.  
  2307.  // EXAMPLE MANIP-11
  2308.  
  2309.  // THE endl MANIPULATOR
  2310.  
  2311.  #include <header.h>
  2312.  
  2313.  int main()
  2314.  {
  2315.     cout << 1
  2316.          << endl
  2317.          << 2
  2318.          << endl ;
  2319.  
  2320.     return 0 ;
  2321.  }
  2322.  
  2323. The output of this program is:
  2324.  
  2325. 1
  2326. 2
  2327.  
  2328. The manipulators "dec", "oct" and "hex" work for both input and output
  2329. operations, and set the stream state accordingly. For example,
  2330.  
  2331.  // EXAMPLE MANIP-12
  2332.  
  2333.  // SETTING THE STREAM STATES USING
  2334.  // MANIPULATORS
  2335.  
  2336.  #include <header.h>
  2337.  
  2338.  int main()
  2339.  {
  2340.     cout << "Input a hex number: " ;
  2341.     int number ;
  2342.     cin >> hex >> number ;
  2343.     cout << "The number in octal is "
  2344.          << oct
  2345.          << number
  2346.          << endl ;
  2347.  
  2348.     return 0 ;
  2349.  }
  2350.  
  2351. If you enter the number '1f' (hex), you will then see the number 37 (octal).
  2352.  
  2353. Recall that when using the function "get" with 3 arguments to read in a
  2354. string, both leading and embedded whitespace are retained. If you want to
  2355. bypass the leading whitespace, and still retain the embedded whitespace,
  2356. then use the input manipulator "ws". In this program enter some leading
  2357. whitespace, then some significant characters including embedded
  2358. whitespace.
  2359.  
  2360.  // EXAMPLE MANIP-13
  2361.  
  2362.  // DEMONSTRATE HOW TO READ IN A
  2363.  // STRING AND RETAIN EMBEDDED
  2364.  // WHITE SPACE, BUT BYPASS
  2365.  // LEADING WHITE SPACE
  2366.  
  2367.  #include <header.h>
  2368.  
  2369.  const int length = 100 ;
  2370.  
  2371.  int main()
  2372.  {
  2373.     char string [length] ;
  2374.     const char quote = '\"' ;
  2375.  
  2376.     cout << "Enter a string: " ;
  2377.     cin >> ws ;
  2378.     cin.get(string , length) ;
  2379.     cout << "Your string: "
  2380.          << quote
  2381.          << string
  2382.          << quote
  2383.          << endl ;
  2384.  
  2385.     return 0 ;
  2386.  }
  2387.  
  2388. There is one other built-in manipulator that takes no argument: "ends". This
  2389. causes a null character to be output, and is useful for objects of type
  2390. strstream .
  2391.  
  2392. ******************************************************************
  2393. Built-in Manipulators Taking 1 Argument
  2394.  
  2395. Because a manipulator that takes 1 argument requires special handling by
  2396. the compiler, a separate header file  must  be included with each program.
  2397. This file is called <iomanip.h>. Note that in the file <header.h> it is
  2398. automatically included.
  2399.  
  2400. Perhaps the most frequently used manipulator taking an argument is "setw".
  2401. Like its counterpart, the member function "width()", it is used to set the
  2402. field width  for the next output item only.  But since manipulators are
  2403. designed to be coded 'in line' with data to be output, they do not return a
  2404. value (which would cause spurious data to appear in the output buffer). The
  2405. one argument is, of course, the field width itself.
  2406.  
  2407. Here is example OUTPUT-41 again, this time using a manipulator to set the
  2408. field width.
  2409.  
  2410.  // EXAMPLE MANIP-21
  2411.  
  2412.  // HOW TO SET THE FIELD WIDTH
  2413.  // USING A MANIPULATOR
  2414.  
  2415.  #include <header.h>
  2416.  
  2417.  int main()
  2418.  {
  2419.     cout << setw(5)
  2420.          << 1
  2421.          << endl ;
  2422.     cout << setw(5)
  2423.          << 23
  2424.          << endl ;
  2425.  
  2426.     return 0 ;
  2427.  }
  2428.  
  2429. Another frequently used manipulator is the one that sets the fill character.
  2430. It is called "setfill" and, as you would expect, the 1 argument is the fill
  2431. character itself.
  2432.  
  2433. Here is example OUTPUT-52 again, this time using manipulators to set the
  2434. field width and fill character.
  2435.  
  2436.  // EXAMPLE MANIP-22
  2437.  
  2438.  // A COMBINATION OF SETTING THE
  2439.  // FIELD WIDTH AND SPECIFYING
  2440.  // THE FILL CHARACTER USING
  2441.  // MANIPULATORS
  2442.  
  2443.  #include <header.h>
  2444.  
  2445.  int main()
  2446.  {
  2447.     cout << setw(5)
  2448.          << setfill('0')
  2449.          << 1
  2450.          << endl ;
  2451.     cout << setw(5)
  2452.          << setfill('*')
  2453.          << 23
  2454.          << endl ;
  2455.  
  2456.     return 0 ;
  2457.  }
  2458.  
  2459. The other manipulators that take an argument are:
  2460.  
  2461.    resetiosflags(long flag)  -- turns off the bits specified in "flag"
  2462.                                 (input and output)
  2463.    setbase(int base)  -- sets the output base to decimal if "base" if 0
  2464.                          or 10; to octal if "base" is 8; to hexadecimal
  2465.                          if "base" is 16 (output)
  2466.    setiosflags(long flag)  -- turns on the bits specified in "flag" (input
  2467.                               and output)
  2468.    setprecision(int prec)  -- sets the number of digits displayed after the
  2469.                               decimal point to "prec" (output)
  2470.  
  2471. ******************************************************************
  2472. Creating Your Own Manipulators Taking 1 Argument
  2473.  
  2474. The explanation of how manipulators taking 1 argument are handled by the
  2475. compiler is too complex to be explained here, so let's just see how it is
  2476. coded.
  2477.  
  2478. First, the generic form (assuming output) of the manipulator is:
  2479.  
  2480.  ostream& manipulator-name(ostream& strm , type arg)
  2481.  {
  2482.    // your code here using arg
  2483.    return strm ;
  2484.  }
  2485.  
  2486. where "type" is either "int" or "long", and "arg" is the formal argument name.
  2487.  
  2488. Next, you must include this code:
  2489.  
  2490.  OMANIP(type) manipulator-name(type arg)
  2491.  {
  2492.     return OMANIP(type) (manipulator-name , arg) ;
  2493.  }
  2494.  
  2495. where "OMANIP" is a class defined in <iomanip.h>.
  2496.  
  2497. For example, here is a manipulator called "manip" that sets the field width to
  2498. whatever the argument happens to be, and also sets the fill character to '*'.
  2499.  
  2500.  // EXAMPLE MANIP-31
  2501.  
  2502.  // HOW TO CREATE A MANIPULATOR THAT
  2503.  // TAKES 1 ARGUMENT
  2504.  
  2505.  #include <header.h>
  2506.  
  2507.  ostream& manip(ostream& strm , int length)
  2508.  {
  2509.     strm << setw(length) << setfill('*') ;
  2510.     return strm ;
  2511.  }
  2512.  
  2513.  OMANIP(int) manip(int length)
  2514.  {
  2515.     return OMANIP(int) (manip , length) ;
  2516.  }
  2517.  
  2518.  int main()
  2519.  {
  2520.     cout << manip(7)
  2521.          << 123
  2522.          << endl ;
  2523.     cout << manip(5)
  2524.          << 45
  2525.          << endl ;
  2526.  
  2527.     return 0 ;
  2528.  }
  2529.  
  2530. The output of this program is:
  2531.  
  2532. ****123
  2533. ***45
  2534.  
  2535. If you wish to use a type other than "int" or "long", then you must include the
  2536. following statement:
  2537.  
  2538.   IOMANIPdeclare(type) ;
  2539.  
  2540. where "type" is either "char", "float", "double", etc.
  2541.  
  2542. Here is the same example, but now it is the fill character that is variable.
  2543.  
  2544.  // EXAMPLE MANIP-32
  2545.  
  2546.  // HOW TO CREATE A MANIPULATOR THAT
  2547.  // TAKES 1 ARGUMENT, AND THAT ARGUMENT
  2548.  // IS NOT int OR long
  2549.  
  2550.  #include <header.h>
  2551.  
  2552.  // Don't forget this statement
  2553.  IOMANIPdeclare(char) ;
  2554.  
  2555.  ostream& manip(ostream& strm , char ch)
  2556.  {
  2557.     strm << setw(7) << setfill(ch) ;
  2558.     return strm ;
  2559.  }
  2560.  
  2561.  OMANIP(char) manip(char ch)
  2562.  {
  2563.     return OMANIP(char) (manip , ch) ;
  2564.  }
  2565.  
  2566.  int main()
  2567.  {
  2568.     cout << manip('*')
  2569.          << 123
  2570.          << endl ;
  2571.     cout << manip('$')
  2572.          << 45
  2573.          << endl ;
  2574.  
  2575.     return 0 ;
  2576.  }
  2577.  
  2578. The output of this program is:
  2579.  
  2580. ****123
  2581. $$$$$45
  2582.  
  2583. Finally, take a look at the file <header.h> for some useful manipulators that
  2584. have already been defined for you.
  2585.  
  2586. ************************* SECTION 5 -- FILE I/O ****************************
  2587.  
  2588. Introduction
  2589.  
  2590. File input/output using <iostream.h> involves any of these 3 operations:
  2591.  
  2592.  1) Reading a file
  2593.  2) Writing a file
  2594.  3) Both reading and writing a file
  2595.  
  2596. To handle these operations, special classes have already been defined. They
  2597. are:
  2598.  
  2599.  Read -- class  ifstream  (derived from  istream )
  2600.  Write -- class  ofstream  (derived from  ostream )
  2601.  Both -- class "fstream" (derived from  iostream )
  2602.  
  2603. To use any of these classes, you must:
  2604.  
  2605.   #include <fstream.h>
  2606.  
  2607. which automatically includes the header file <iostream.h>. (The file
  2608. <fstream.h> is already included in <header.h>.)
  2609.  
  2610. There are no pre-defined instances of these classes comparable to "cin" and
  2611. "cout". Therefore, the first step in using file I/O is to create an instance of the
  2612. appropriate class, e.g.,
  2613.  
  2614.   ifstream file_in ;
  2615.   ofstream file_out ;
  2616.   fstream  file_both ;
  2617.  
  2618. ****************************************************************
  2619. Using the instances
  2620.  
  2621. The first step in using the file instances is to open the disk file. In any
  2622. computer language this means establishing a communication link between
  2623. your code and the external file. Each of the 3 classes provides the member
  2624. function called  open  to do this. The declarations for these  open  functions
  2625. are as follows:
  2626.  
  2627.   void ifstream::open(const char* name ,
  2628.                       int m = ios::in ,
  2629.                       int prot = filebuf::openprot) ;
  2630.  
  2631.   void ofstream::open(const char* name ,
  2632.                       int m = ios::out ,
  2633.                       int prot = filebuf::openprot) ;
  2634.  
  2635.   void fstream::open(const char* name ,
  2636.                      int m,
  2637.                      int prot = filebuf::openprot) ;
  2638.  
  2639. The first argument is the external file name passed in as a constant string
  2640. literal.
  2641.  
  2642. The second argument is the file mode, and comes from a  public
  2643. enumerated type in the class "ios". There are eight possible modes, as
  2644. follows:
  2645.  
  2646.     ios::in        Input mode. (Default for input file.)
  2647.     ios::out       Output mode. (Default for output file.)
  2648.     ios::app       Append to an output file rather than update an existing
  2649.                    record.
  2650.     ios::ate       Position file marker at end of file instead of beginning.
  2651.     ios::trunc     Delete file if it exists and re-create it.
  2652.     ios::nocreate  File must exist, otherwise open fails (output only)
  2653.     ios::noreplace File must not exist, otherwise open fails (output only)
  2654.     ios::binary    Binary mode; default is text (Binary is a Borland
  2655.                    enhancement)
  2656.  
  2657. Note that for "fstream" instances, there is no default mode. Obviously, these
  2658. various modes may be bitwise ORed together if more than one is desired.
  2659.  
  2660. The third argument is the file access. Under Turbo C++ version 1.01, the
  2661. possible values are:
  2662.  
  2663.     0 = Default
  2664.     1 = Read-only file
  2665.     2 = Hidden file
  2666.     4 = System file
  2667.     8 = Archive bit set
  2668.  
  2669. If the open fails, the overloaded "operator!" used on the instance will
  2670. return 'true'.
  2671.  
  2672. For example:
  2673.  
  2674.     file_in.open("INPUT") ;
  2675.     file_out.open("OUTPUT") ;
  2676.     file_both.open("BOTH" , ios::in | ios::out) ;
  2677.  
  2678. An alternate method of calling the open function is to call the constructor
  2679. with the same argument(s) that you would use for the "open". Thus, instead
  2680. of creating the instance and then explicitly calling the "open" function, you
  2681. can combine these two steps by writing:
  2682.  
  2683.    ifstream file_in("INPUT") ;
  2684.    ofstream file_out("OUTPUT") ;
  2685.    fstream  file_both("BOTH", ios::in | ios::out) ;
  2686.  
  2687. When you are done using the file, the member function "close" taking no
  2688. arguments will close it. This function is called automatically by the
  2689. destructor for the class, but you may call it explicitly if you wish.
  2690.  
  2691. Let's start with a simple program that accepts string input from the user
  2692. and writes it to a disk file called "OUTPUT.DAT".
  2693.  
  2694. // EXAMPLE FILEIO-01
  2695.  
  2696. // CREATE AN OUTPUT FILE AND WRITE
  2697. // WHATEVER DATA THE OPERATOR MAY
  2698. // ENTER
  2699.  
  2700. #include <header.h>
  2701.  
  2702. const int max = 100 ;
  2703.  
  2704. ////////////////////////////////////
  2705.  
  2706. int main()
  2707. {
  2708.    char buffer[max] ;
  2709.    ofstream file_out("OUTPUT.DAT") ;
  2710.    if (!file_out)
  2711.    {
  2712.       cout << "OPEN FAILED\n" ;
  2713.       PAUSE() ;
  2714.       exit(1) ;
  2715.    }
  2716.  
  2717.    cout << "Enter a line of data: " ;
  2718.    while (!cin.get(buffer , max).eof())
  2719.    {
  2720.       file_out << buffer << endl ;
  2721.       cout << "Next line: " ;
  2722.       cin >> FLUSH ;
  2723.    }
  2724.  
  2725.    return 0 ;
  2726. }
  2727.  
  2728. Now give the user a chance to append more records to the file. Note that
  2729. the mode of the file is "ios::out | ios::app" (although "ios::app" by itself
  2730. would still have worked).
  2731.  
  2732. // EXAMPLE FILEIO-02
  2733.  
  2734. // GIVE THE USER A CHANCE TO APPEND
  2735. // RECORDS TO THE FILE
  2736.  
  2737. #include <header.h>
  2738.  
  2739. const int max = 100 ;
  2740.  
  2741. ////////////////////////////////////
  2742.  
  2743. int main()
  2744. {
  2745.    char buffer[max] ;
  2746.    ofstream file_out("OUTPUT.DAT" , ios::out | ios::app) ;
  2747.    if (!file_out)
  2748.    {
  2749.       cout << "OPEN FAILED\n" ;
  2750.       PAUSE() ;
  2751.       exit(1) ;
  2752.    }
  2753.  
  2754.    cout << "Enter a line of data: " ;
  2755.    while (!cin.get(buffer , max).eof\())
  2756.    {
  2757.       file_out << buffer << endl ;
  2758.       cout << "Next line: " ;
  2759.       cin >> FLUSH ;
  2760.    }
  2761.  
  2762.    return 0 ;
  2763. }
  2764.  
  2765. Finally, this program numbers and prints the records that were just written.
  2766.  
  2767. // EXAMPLE FILEIO-03
  2768.  
  2769. // NOW READ THE FILE THAT WAS JUST
  2770. // CREATED
  2771.  
  2772. #include <header.h>
  2773.  
  2774. const int max = 100 ;
  2775.  
  2776. ////////////////////////////////////
  2777.  
  2778. int main()
  2779. {
  2780.    char buffer[max] ;
  2781.    ifstream file_in("OUTPUT.DAT") ;
  2782.    if (!file_in)
  2783.    {
  2784.       cout << "OPEN FAILED\n" ;
  2785.       PAUSE() ;
  2786.       exit(1) ;
  2787.    }
  2788.  
  2789.    int rec = 0 ;
  2790.    while (!file_in.get(buffer , max).eof())
  2791.    {
  2792.       cout << "Record #"
  2793.            << ++rec
  2794.            << ": "
  2795.            << buffer
  2796.            << endl ;
  2797.       file_in >> FLUSH ;
  2798.    }
  2799.  
  2800.    return 0 ;
  2801. }
  2802.  
  2803. ****************************************************************
  2804. The File Position Markers
  2805.  
  2806. So that the file I/O classes can keep track of where in a file the data is
  2807. to be written to and read from, they establish what is called a 'file position
  2808. marker' (fpm). On Turbo C++ this marker has been 'typedef'ed as a 'long'
  2809. integer representing an offset value from the beginning of the file. In point
  2810. of fact, there are two such markers, one for reading, and one for writing.
  2811. You may alter these markers by using two member functions: "seekg" and
  2812. "seekp". "seekg" is associated with the file's 'get or read' pointer, and
  2813. "seekp" with the file's 'put or write' pointer. The declarations for these two
  2814. functions are as follows:
  2815.  
  2816.   istream& istream::seekg(streampos offset) ;
  2817.   istream& istream::seekg(streamoff offset , seek_dir) ;
  2818.  
  2819.   ostream& ostream::seekp(streampos offset) ;
  2820.   ostream& ostream::seekp(streamoff offset , seek_dir) ;
  2821.  
  2822. where "streampos" and "streamoff" represent "long" integers, and "seek_dir"
  2823. is an enumerated type defined as follows:
  2824.  
  2825.   enum seek_dir {ios::beg , ios::cur , ios::end} ;
  2826.  
  2827. If the 1-argument form of the function is used, then "offset" is the offset
  2828. from the beginning of the file. If the 2-argument form is used, then "offset"
  2829. is the offset number of bytes (positive or negative) from the absolute
  2830. "seek_dir" position. Therefore, a call to "seekg" with an argument of 0 causes
  2831. the file to rewind and data to be read starting with the first record.
  2832.  
  2833. To find out the positions of these markers, you may use the member functions
  2834. "tellg" and "tellp". They are declared as follows:
  2835.  
  2836.   streampos istream::tellg() ;
  2837.   streampos ostream::tellp() ;
  2838.  
  2839. To illustrate this, here is the previous example of writing and reading a
  2840. file, but now it uses an instance of the class "fstream" so that the output and
  2841. input can be combined. After each record is read and printed, the file
  2842. position marker (fpm) is displayed. NOTE: The inclusion of the mode
  2843. "ios::binary" is to avoid a Borland bug with "tellg" corrupting the fpm.
  2844.  
  2845. // EXAMPLE FILEIO-04
  2846.  
  2847. // HOW TO WRITE AND READ A FILE IN
  2848. // THE SAME PROGRAM
  2849.  
  2850. // NOTE: FILE IS OPENED IN BINARY
  2851. // MODE TO AVOID A tellg BUG IN
  2852. // TURBO C++
  2853.  
  2854. #include <header.h>
  2855.  
  2856. const int max = 100 ;
  2857.  
  2858. ////////////////////////////////////
  2859.  
  2860. int main()
  2861. {
  2862.    char buffer[max] ;
  2863.   "fstream"file_both("BOTH.DAT" ,
  2864.                       ios::in |
  2865.                       ios::out |
  2866.                       ios::binary) ;
  2867.    if (!file_both)
  2868.    {
  2869.       cout << "OPEN FAILED\n" ;
  2870.       PAUSE() ;
  2871.       exit(1) ;
  2872.    }
  2873.  
  2874.    cout << "Enter a line of data: " ;
  2875.    while (!cin.get(buffer , max).eof())
  2876.    {
  2877.       file_both << buffer << endl ;
  2878.       cout << "Next line: " ;
  2879.       cin >> FLUSH ;
  2880.    }
  2881.  
  2882.    // Flush the output buffer
  2883.    file_both << flush ;
  2884.  
  2885.    // Return to the start of the file
  2886.    file_both.seekg(0) ;
  2887.  
  2888.    // Read and print the records, and
  2889.    // show the file position marker
  2890.    int rec = 0 ;
  2891.    while (!file_both.get(buffer , max).eof())
  2892.    {
  2893.       cout << "Record #"
  2894.            << ++rec
  2895.            << ": "
  2896.            << buffer
  2897.            << endl ;
  2898.       cout << "fpm is: "
  2899.            << file_both.tellg()
  2900.            << endl ;
  2901.       file_both >> FLUSH ;
  2902.    }
  2903.  
  2904.    return 0 ;
  2905. }
  2906.  
  2907. This program gives the user complete flexibility as to the name of the
  2908. external file to be manipulated, and modes to be used. NOTE: Do not try to
  2909. include an instance of a file class within a class declaration. As of version
  2910. 1.01, there is a bug which does not allow this. As an avoidance technique,
  2911. you may include a pointer of the class type, and then obtain the space for
  2912. the instance via the "new" operator.
  2913.  
  2914. // EXAMPLE FILEIO-05
  2915.  
  2916. // GIVE THE USER COMPLETE FLEXIBILITY
  2917. // AS TO THE MODE OF THE FILE AND THE
  2918. // DATA WRITTEN AND READ
  2919.  
  2920. // ARGUMENTS ARE ENTERED FROM THE DOS
  2921. // COMMAND LINE. THE FIRST ARGUMENT
  2922. // IS THE DISK FILE NAME, AND THE
  2923. // REMAINING ARGUMENTS REPRESENT THE
  2924. // VARIOUS OPEN MODES, EXACTLY AS
  2925. // SPECIFIED BY THE ENUMERATED TYPES
  2926.  
  2927. // NOTE THAT A CLASS IS NOW USED TO
  2928. // CONTROL THE VARIOUS OPERATIONS ON
  2929. // A FILE OBJECT. HOWEVER, A POINTER
  2930. // IS DECLARED INSTEAD OF AN INSTANCE
  2931. // TO AVOID A BORLAND BUG
  2932.  
  2933. #include <header.h>
  2934.  
  2935. const int max = 100 ;
  2936.  
  2937. class file
  2938. {
  2939.    fstream* ptr ;
  2940.      public:
  2941.  
  2942.    file()
  2943.    {
  2944.       ptr = new fstream() ;
  2945.    }
  2946.  
  2947.    int open(int argc , char* argv[]) ;
  2948.    void read() ;
  2949.    void write() ;
  2950.    void beginning() ;
  2951.    void end() ;
  2952.    void close() ;
  2953. } ;
  2954.  
  2955. // Open the file by setting up the
  2956. // field 'mode' with the OR of what-
  2957. // ever modes the user has chosen
  2958.  
  2959. int file::open(int argc , char* argv[])
  2960. {
  2961.    int mode = 0 ;
  2962.  
  2963.    for (int i = 2 ; i < argc ; ++i)
  2964.    {
  2965.       if (!strcmp (argv[i] , "out"))
  2966.           mode |= ios::out ;
  2967.       else if (!strcmp (argv[i] , "in"))
  2968.           mode |= ios::in ;
  2969.       else if (!strcmp (argv[i] , "app"))
  2970.           mode |= ios::app ;
  2971.       else if (!strcmp (argv[i] , "ate"))
  2972.           mode |= ios::ate ;
  2973.       else if (!strcmp (argv[i] , "trunc"))
  2974.           mode |= ios::trunc ;
  2975.       else if (!strcmp (argv[i] , "nocreate"))
  2976.           mode |= ios::nocreate ;
  2977.       else if (!strcmp (argv[i] , "noreplace"))
  2978.           mode |= ios::noreplace ;
  2979.       else if (!strcmp (argv[i] , "binary"))
  2980.           mode |= ios::binary ;
  2981.       else
  2982.           cout << "Invalid mode: "
  2983.                 << argv[i]
  2984.                 << endl ;
  2985.    }
  2986.  
  2987.    // Perform the actual open
  2988.    ptr->open(argv[1] , mode) ;
  2989.  
  2990.    // If an error occurred, return
  2991.    // "true"
  2992.    return (!*ptr) ;
  2993. }
  2994.  
  2995. // Read the file
  2996.  
  2997. void file::read()
  2998. {
  2999.    char buffer [max] ;
  3000.  
  3001.    cout << "Data line: " ;
  3002.    ptr->get(buffer , max) ;
  3003.    *ptr >> FLUSH ;
  3004.    if (!(ptr->eof()))
  3005.       cout << buffer << endl ;
  3006.    else
  3007.       cout << "EOF\n" ;
  3008.    ptr->clear() ;
  3009. }
  3010.  
  3011. // Write the file
  3012.  
  3013. void file::write()
  3014. {
  3015.    char buffer [max] ;
  3016.  
  3017.    cout << "Enter some data: " ;
  3018.    cin.get(buffer , max) ;
  3019.    cin >> FLUSH ;
  3020.    *ptr << buffer << endl ;
  3021. }
  3022.  
  3023. // Return to the start of the file
  3024.  
  3025. void file::beginning()
  3026. {
  3027.    ptr->seekg(0) ;
  3028.    ptr->seekp(0) ;
  3029. }
  3030.  
  3031. // Seek to the end of the file
  3032.  
  3033. void file::end()
  3034. {
  3035.    ptr->seekg(0 , ios::end) ;
  3036.    ptr->seekp(0 , ios::end) ;
  3037. }
  3038.  
  3039. // Close the file
  3040.  
  3041. void file::close()
  3042. {
  3043.    ptr->close() ;
  3044. }
  3045.  
  3046. ///////////////////////////////////
  3047.  
  3048. char menu() ;
  3049.  
  3050. int main(int argc , char* argv [])
  3051. {
  3052.    file my_file ;
  3053.  
  3054.    if (argc < 2)
  3055.    {
  3056.       cout << "NO FILE NAME\n" ;
  3057.       exit(1) ;
  3058.    }
  3059.  
  3060.    if(my_file.open(argc , argv))
  3061.    {
  3062.       cout << "OPEN FAILED\n" ;
  3063.       exit(2) ;
  3064.    }
  3065.  
  3066.    char ch ;
  3067.    while ((ch = menu()) != 'X')
  3068.    {
  3069.       switch (ch)
  3070.       {
  3071.         case 'R' : my_file.read() ;
  3072.                    break ;
  3073.         case 'W' : my_file.write() ;
  3074.                    break ;
  3075.         case 'B' : my_file.beginning() ;
  3076.                    break ;
  3077.         case 'E' : my_file.end() ;
  3078.                    break ;
  3079.         default :  cout << "INVALID\n" ;
  3080.                    break ;
  3081.       }
  3082.    }
  3083.    my_file.close() ;
  3084.  
  3085.    return 0 ;
  3086. }
  3087.  
  3088. ///////////////////////////////////////
  3089.  
  3090. char menu()
  3091. {
  3092.    cout << "\t(R)ead a record\n" ;
  3093.    cout << "\t(W)rite a record\n" ;
  3094.    cout << "\t(B)eginning of file\n" ;
  3095.    cout << "\t(E)nd of the file\n" ;
  3096.    cout << "\te(X)it\n" ;
  3097.  
  3098.    cout << "\n\tYour choice: " ;
  3099.    char ch ;
  3100.    cin >> ch >> FLUSH ;
  3101.    return (toupper(ch)) ;
  3102. }
  3103.  
  3104. ****************************************************************
  3105. Using the Line Printer
  3106.  
  3107. The line printer is just another output file insofar as DOS is concerned. To
  3108. redirect output to a printer from within your program, use the predefined
  3109. name "prn".
  3110.  
  3111. // EXAMPLE FILEIO-06
  3112.  
  3113. // HOW TO PRINT FROM WITHIN A
  3114. // PROGRAM
  3115.  
  3116. #include <header.h>
  3117.  
  3118. int main()
  3119. {
  3120.    ofstream printer ;
  3121.    // "prn" is the DOS printer
  3122.    printer.open("prn") ;
  3123.    if (!printer)
  3124.    {
  3125.      cerr << "Can't open\n" ;
  3126.      exit(1) ;
  3127.    }
  3128.    printer << "This line appears"
  3129.            << " on the printer\n" ;
  3130.  
  3131.    return 0 ;
  3132. }
  3133.  
  3134.